mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
Various improvements
This commit is contained in:
parent
df2354e9bb
commit
701fe95891
@ -273,7 +273,7 @@ private extension CGSize {
|
||||
|
||||
private func convertLottieImage(data: Data) -> UIImage? {
|
||||
let decompressedData = TGGUnzipData(data, 512 * 1024) ?? data
|
||||
guard let animation = LottieInstance(data: decompressedData, fitzModifier: .none, cacheKey: "") else {
|
||||
guard let animation = LottieInstance(data: decompressedData, fitzModifier: .none, colorReplacements: nil, cacheKey: "") else {
|
||||
return nil
|
||||
}
|
||||
let size = animation.dimensions.fitted(CGSize(width: 200.0, height: 200.0))
|
||||
|
@ -7503,4 +7503,20 @@ Sorry for the inconvenience.";
|
||||
"PeerInfo.DeleteChannelText" = "Are you sure you want to delete the channel **%@** and all of its messages for all subscribers of the channel?";
|
||||
|
||||
"Chat.SaveForNotifications" = "Save for Notifications";
|
||||
|
||||
"Group.Setup.WhoCanSendMessages.Title" = "WHO CAN SEND MESSAGES?";
|
||||
"Group.Setup.WhoCanSendMessages.Everyone" = "Everyone";
|
||||
"Group.Setup.WhoCanSendMessages.OnlyMembers" = "Only Members";
|
||||
|
||||
"Group.Setup.ApproveNewMembers" = "Approve New Members";
|
||||
"Group.Setup.ApproveNewMembersInfo" = "Turn this on if you want users to be able to send messages only after they are approved by an admin.";
|
||||
|
||||
"Gallery.GifSaved" = "GIF Saved";
|
||||
|
||||
"Group.JoinGroup" = "Join Group";
|
||||
"Group.ApplyToJoin" = "Apply to Join Group";
|
||||
|
||||
"Group.RequestToJoinSent" = "Request to join sent";
|
||||
"Group.RequestToJoinSentDescriptionGroup" = "You will be able to send messages once the admins approve your request.";
|
||||
|
||||
"Channel.AdminLog.JoinedViaPublicRequest" = "%1$@ joined via public request, approved by %2$@";
|
||||
|
@ -587,7 +587,7 @@ final class AnimatedStickerDirectFrameSource: AnimatedStickerFrameSource {
|
||||
self.currentFrame = 0
|
||||
let decompressedData = TGGUnzipData(data, 8 * 1024 * 1024) ?? data
|
||||
|
||||
guard let animation = LottieInstance(data: decompressedData, fitzModifier: fitzModifier?.lottieFitzModifier ?? .none, cacheKey: "") else {
|
||||
guard let animation = LottieInstance(data: decompressedData, fitzModifier: fitzModifier?.lottieFitzModifier ?? .none, colorReplacements: nil, cacheKey: "") else {
|
||||
return nil
|
||||
}
|
||||
self.animation = animation
|
||||
|
@ -1143,7 +1143,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
|
||||
text = current.inputText.attributedSubstring(from: NSMakeRange(current.selectionRange.lowerBound, current.selectionRange.count)).string
|
||||
return (current, inputMode)
|
||||
}
|
||||
let _ = speakText(text)
|
||||
let _ = speakText(context: self.context, text: text)
|
||||
|
||||
if #available(iOS 13.0, *) {
|
||||
UIMenuController.shared.hideMenu()
|
||||
|
@ -181,19 +181,19 @@ public class ChatListItem: ListViewItem, ChatListSearchItemNeighbour {
|
||||
}
|
||||
}
|
||||
|
||||
private let pinIcon = ItemListRevealOptionIcon.animation(animation: "anim_pin", scale: 0.33333, offset: 0.0, keysToColor: nil, flip: false)
|
||||
private let unpinIcon = ItemListRevealOptionIcon.animation(animation: "anim_unpin", scale: 0.33333, offset: 0.0, keysToColor: ["un Outlines.Group 1.Stroke 1"], flip: false)
|
||||
private let muteIcon = ItemListRevealOptionIcon.animation(animation: "anim_mute", scale: 0.33333, offset: 0.0, keysToColor: ["un Outlines.Group 1.Stroke 1"], flip: false)
|
||||
private let unmuteIcon = ItemListRevealOptionIcon.animation(animation: "anim_unmute", scale: 0.33333, offset: 0.0, keysToColor: nil, flip: false)
|
||||
private let deleteIcon = ItemListRevealOptionIcon.animation(animation: "anim_delete", scale: 0.33333, offset: 0.0, keysToColor: nil, flip: false)
|
||||
private let groupIcon = ItemListRevealOptionIcon.animation(animation: "anim_group", scale: 0.33333, offset: 0.0, keysToColor: nil, flip: false)
|
||||
private let ungroupIcon = ItemListRevealOptionIcon.animation(animation: "anim_ungroup", scale: 0.33333, offset: 0.0, keysToColor: nil, flip: false)
|
||||
private let readIcon = ItemListRevealOptionIcon.animation(animation: "anim_read", scale: 0.33333, offset: 0.0, keysToColor: nil, flip: false)
|
||||
private let unreadIcon = ItemListRevealOptionIcon.animation(animation: "anim_unread", scale: 0.33333, offset: 0.0, keysToColor: ["Oval.Oval.Stroke 1"], flip: false)
|
||||
private let archiveIcon = ItemListRevealOptionIcon.animation(animation: "anim_archive", scale: 0.33333, offset: 2.0, keysToColor: ["box2.box2.Fill 1"], flip: false)
|
||||
private let unarchiveIcon = ItemListRevealOptionIcon.animation(animation: "anim_unarchive", scale: 0.16214, offset: -9.0, keysToColor: ["box2.box2.Fill 1"], flip: false)
|
||||
private let hideIcon = ItemListRevealOptionIcon.animation(animation: "anim_hide", scale: 0.33333, offset: 2.0, keysToColor: ["Path 2.Path 2.Fill 1"], flip: false)
|
||||
private let unhideIcon = ItemListRevealOptionIcon.animation(animation: "anim_hide", scale: 0.33333, offset: -20.0, keysToColor: ["Path 2.Path 2.Fill 1"], flip: true)
|
||||
private let pinIcon = ItemListRevealOptionIcon.animation(animation: "anim_pin", scale: 1.0, offset: 0.0, replaceColors: nil, flip: false)
|
||||
private let unpinIcon = ItemListRevealOptionIcon.animation(animation: "anim_unpin", scale: 1.0, offset: 0.0, replaceColors: [0x1993fa], flip: false)
|
||||
private let muteIcon = ItemListRevealOptionIcon.animation(animation: "anim_mute", scale: 1.0, offset: 0.0, replaceColors: [0xff9500], flip: false)
|
||||
private let unmuteIcon = ItemListRevealOptionIcon.animation(animation: "anim_unmute", scale: 1.0, offset: 0.0, replaceColors: nil, flip: false)
|
||||
private let deleteIcon = ItemListRevealOptionIcon.animation(animation: "anim_delete", scale: 1.0, offset: 0.0, replaceColors: nil, flip: false)
|
||||
private let groupIcon = ItemListRevealOptionIcon.animation(animation: "anim_group", scale: 1.0, offset: 0.0, replaceColors: nil, flip: false)
|
||||
private let ungroupIcon = ItemListRevealOptionIcon.animation(animation: "anim_ungroup", scale: 1.0, offset: 0.0, replaceColors: nil, flip: false)
|
||||
private let readIcon = ItemListRevealOptionIcon.animation(animation: "anim_read", scale: 1.0, offset: 0.0, replaceColors: nil, flip: false)
|
||||
private let unreadIcon = ItemListRevealOptionIcon.animation(animation: "anim_unread", scale: 1.0, offset: 0.0, replaceColors: [0x2194fa], flip: false)
|
||||
private let archiveIcon = ItemListRevealOptionIcon.animation(animation: "anim_archive", scale: 1.0, offset: 2.0, replaceColors: [0xa9a9ad], flip: false)
|
||||
private let unarchiveIcon = ItemListRevealOptionIcon.animation(animation: "anim_unarchive", scale: 0.486, offset: -9.0, replaceColors: [0xa9a9ad], flip: false)
|
||||
private let hideIcon = ItemListRevealOptionIcon.animation(animation: "anim_hide", scale: 1.0, offset: 2.0, replaceColors: [0xbdbdc2], flip: false)
|
||||
private let unhideIcon = ItemListRevealOptionIcon.animation(animation: "anim_hide", scale: 1.0, offset: -20.0, replaceColors: [0xbdbdc2], flip: true)
|
||||
|
||||
private enum RevealOptionKey: Int32 {
|
||||
case pin
|
||||
|
@ -26,7 +26,7 @@ public func reactionStaticImage(context: AccountContext, animation: TelegramMedi
|
||||
guard let unpackedData = TGGUnzipData(data, 5 * 1024 * 1024) else {
|
||||
return
|
||||
}
|
||||
guard let instance = LottieInstance(data: unpackedData, fitzModifier: .none, cacheKey: "") else {
|
||||
guard let instance = LottieInstance(data: unpackedData, fitzModifier: .none, colorReplacements: nil, cacheKey: "") else {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -352,7 +352,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
window.rootViewController?.present(controller, animated: true)
|
||||
}
|
||||
case .speak:
|
||||
let _ = speakText(string)
|
||||
let _ = speakText(context: strongSelf.context, text: string)
|
||||
case .translate:
|
||||
if let parentController = strongSelf.baseNavigationController()?.topViewController as? ViewController {
|
||||
let controller = TranslateScreen(context: strongSelf.context, text: string, fromLanguage: nil)
|
||||
|
@ -432,15 +432,15 @@ public func inviteLinkEditController(context: AccountContext, updatedPresentatio
|
||||
let actionsDisposable = DisposableSet()
|
||||
|
||||
let initialState: InviteLinkEditControllerState
|
||||
if let invite = invite {
|
||||
var usageLimit = invite.usageLimit
|
||||
if let limit = usageLimit, let count = invite.count, count > 0 {
|
||||
if let invite = invite, case let .link(_, title, _, requestApproval, _, _, _, _, expireDate, usageLimit, count, _) = invite {
|
||||
var usageLimit = usageLimit
|
||||
if let limit = usageLimit, let count = count, count > 0 {
|
||||
usageLimit = limit - count
|
||||
}
|
||||
|
||||
let timeLimit: InviteLinkTimeLimit
|
||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
if let expireDate = invite.expireDate {
|
||||
if let expireDate = expireDate {
|
||||
if currentTime >= expireDate {
|
||||
timeLimit = .day
|
||||
} else {
|
||||
@ -450,7 +450,7 @@ public func inviteLinkEditController(context: AccountContext, updatedPresentatio
|
||||
timeLimit = .unlimited
|
||||
}
|
||||
|
||||
initialState = InviteLinkEditControllerState(title: invite.title ?? "", usage: InviteLinkUsageLimit(value: usageLimit), time: timeLimit, requestApproval: invite.requestApproval, pickingTimeLimit: false, pickingUsageLimit: false)
|
||||
initialState = InviteLinkEditControllerState(title: title ?? "", usage: InviteLinkUsageLimit(value: usageLimit), time: timeLimit, requestApproval: requestApproval, pickingTimeLimit: false, pickingUsageLimit: false)
|
||||
} else {
|
||||
initialState = InviteLinkEditControllerState(title: "", usage: .unlimited, time: .unlimited, requestApproval: false, pickingTimeLimit: false, pickingUsageLimit: false)
|
||||
}
|
||||
@ -472,7 +472,7 @@ public func inviteLinkEditController(context: AccountContext, updatedPresentatio
|
||||
}, dismissInput: {
|
||||
dismissInputImpl?()
|
||||
}, revoke: {
|
||||
guard let invite = invite else {
|
||||
guard let inviteLink = invite?.link else {
|
||||
return
|
||||
}
|
||||
let _ = (context.account.postbox.loadedPeerWithId(peerId)
|
||||
@ -495,7 +495,7 @@ public func inviteLinkEditController(context: AccountContext, updatedPresentatio
|
||||
dismissAction()
|
||||
dismissImpl?()
|
||||
|
||||
let _ = (context.engine.peers.revokePeerExportedInvitation(peerId: peerId, link: invite.link)
|
||||
let _ = (context.engine.peers.revokePeerExportedInvitation(peerId: peerId, link: inviteLink)
|
||||
|> timeout(10, queue: Queue.mainQueue(), alternate: .fail(.generic))
|
||||
|> deliverOnMainQueue).start(next: { invite in
|
||||
switch invite {
|
||||
@ -578,13 +578,13 @@ public func inviteLinkEditController(context: AccountContext, updatedPresentatio
|
||||
}
|
||||
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
})
|
||||
} else if let initialInvite = invite {
|
||||
if initialInvite.expireDate == expireDate && initialInvite.usageLimit == usageLimit && initialInvite.requestApproval == requestNeeded {
|
||||
} else if let initialInvite = invite, case let .link(link, _, _, initialRequestApproval, _, _, _, _, initialExpireDate, initialUsageLimit, _, _) = initialInvite {
|
||||
if initialExpireDate == expireDate && initialUsageLimit == usageLimit && initialRequestApproval == requestNeeded {
|
||||
completion?(initialInvite)
|
||||
dismissImpl?()
|
||||
return
|
||||
}
|
||||
let _ = (context.engine.peers.editPeerExportedInvitation(peerId: peerId, link: initialInvite.link, title: title, expireDate: expireDate, usageLimit: requestNeeded ? 0 : usageLimit, requestNeeded: requestNeeded)
|
||||
let _ = (context.engine.peers.editPeerExportedInvitation(peerId: peerId, link: link, title: title, expireDate: expireDate, usageLimit: requestNeeded ? 0 : usageLimit, requestNeeded: requestNeeded)
|
||||
|> timeout(10, queue: Queue.mainQueue(), alternate: .fail(.generic))
|
||||
|> deliverOnMainQueue).start(next: { invite in
|
||||
completion?(invite)
|
||||
|
@ -401,8 +401,8 @@ public final class InviteLinkInviteController: ViewController {
|
||||
ActionSheetButtonItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeLink, color: .destructive, action: {
|
||||
dismissAction()
|
||||
|
||||
if let invite = invite {
|
||||
let _ = (context.engine.peers.revokePeerExportedInvitation(peerId: peerId, link: invite.link) |> deliverOnMainQueue).start(next: { result in
|
||||
if let inviteLink = invite?.link {
|
||||
let _ = (context.engine.peers.revokePeerExportedInvitation(peerId: peerId, link: inviteLink) |> deliverOnMainQueue).start(next: { result in
|
||||
if let result = result, case let .replace(_, invite) = result {
|
||||
mainInvitePromise.set(invite)
|
||||
}
|
||||
@ -429,11 +429,11 @@ public final class InviteLinkInviteController: ViewController {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
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
|
||||
guard let strongSelf = self else {
|
||||
guard let strongSelf = self, let inviteLink = invite.link else {
|
||||
return
|
||||
}
|
||||
let updatedPresentationData = (strongSelf.presentationData, strongSelf.presentationDataPromise.get())
|
||||
let shareController = ShareController(context: context, subject: .url(invite.link), updatedPresentationData: updatedPresentationData)
|
||||
let shareController = ShareController(context: context, subject: .url(inviteLink), updatedPresentationData: updatedPresentationData)
|
||||
shareController.completed = { [weak self] peerIds in
|
||||
if let strongSelf = self {
|
||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in
|
||||
|
@ -285,7 +285,7 @@ private func inviteLinkListControllerEntries(presentationData: PresentationData,
|
||||
let mainInvite: ExportedInvitation?
|
||||
var isPublic = false
|
||||
if let peer = peer, let address = peer.addressName, !address.isEmpty && admin == nil {
|
||||
mainInvite = ExportedInvitation(link: "t.me/\(address)", title: nil, isPermanent: true, requestApproval: false, isRevoked: false, adminId: EnginePeer.Id(0), date: 0, startDate: nil, expireDate: nil, usageLimit: nil, count: nil, requestedCount: nil)
|
||||
mainInvite = .link(link: "t.me/\(address)", title: nil, isPermanent: true, requestApproval: false, isRevoked: false, adminId: EnginePeer.Id(0), date: 0, startDate: nil, expireDate: nil, usageLimit: nil, count: nil, requestedCount: nil)
|
||||
isPublic = true
|
||||
} else if let invites = invites, let invite = invites.first(where: { $0.isPermanent && !$0.isRevoked }) {
|
||||
mainInvite = invite
|
||||
@ -300,7 +300,7 @@ private func inviteLinkListControllerEntries(presentationData: PresentationData,
|
||||
let importersCount: Int32
|
||||
if let count = importers?.count {
|
||||
importersCount = count
|
||||
} else if let count = mainInvite?.count {
|
||||
} else if let mainInvite = mainInvite, case let .link(_, _, _, _, _, _, _, _, _, _, count, _) = mainInvite, let count = count {
|
||||
importersCount = count
|
||||
} else {
|
||||
importersCount = 0
|
||||
@ -339,8 +339,10 @@ private func inviteLinkListControllerEntries(presentationData: PresentationData,
|
||||
if let additionalInvites = additionalInvites {
|
||||
var index: Int32 = 0
|
||||
for invite in additionalInvites {
|
||||
entries.append(.link(index, presentationData.theme, invite, canEditLinks, invite.expireDate != nil ? tick : nil))
|
||||
index += 1
|
||||
if case let .link(_, _, _, _, _, _, _, _, expireDate, _, _, _) = invite {
|
||||
entries.append(.link(index, presentationData.theme, invite, canEditLinks, expireDate != nil ? tick : nil))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
} else if let admin = admin, admin.count > 1 {
|
||||
var index: Int32 = 0
|
||||
@ -427,7 +429,10 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio
|
||||
}
|
||||
|
||||
let arguments = InviteLinkListControllerArguments(context: context, shareMainLink: { invite in
|
||||
let shareController = ShareController(context: context, subject: .url(invite.link), updatedPresentationData: updatedPresentationData)
|
||||
guard let inviteLink = invite.link else {
|
||||
return
|
||||
}
|
||||
let shareController = ShareController(context: context, subject: .url(inviteLink), updatedPresentationData: updatedPresentationData)
|
||||
shareController.completed = { peerIds in
|
||||
let _ = (context.account.postbox.transaction { transaction -> [Peer] in
|
||||
var peers: [Peer] = []
|
||||
@ -516,7 +521,7 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio
|
||||
})
|
||||
})))
|
||||
|
||||
if invite.adminId.toInt64() != 0 {
|
||||
if case let .link(_, _, _, _, _, adminId, _, _, _, _, _, _) = 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
|
||||
@ -552,8 +557,8 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio
|
||||
return state
|
||||
}
|
||||
}
|
||||
if revoke {
|
||||
revokeLinkDisposable.set((context.engine.peers.revokePeerExportedInvitation(peerId: peerId, link: invite.link) |> deliverOnMainQueue).start(next: { result in
|
||||
if revoke, let inviteLink = invite.link {
|
||||
revokeLinkDisposable.set((context.engine.peers.revokePeerExportedInvitation(peerId: peerId, link: inviteLink) |> deliverOnMainQueue).start(next: { result in
|
||||
updateState { state in
|
||||
var updatedState = state
|
||||
updatedState.revokingPrivateLink = false
|
||||
@ -626,8 +631,12 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
guard let inviteLink = invite.link else {
|
||||
return
|
||||
}
|
||||
|
||||
let shareController = ShareController(context: context, subject: .url(invite.link), updatedPresentationData: updatedPresentationData)
|
||||
let shareController = ShareController(context: context, subject: .url(inviteLink), updatedPresentationData: updatedPresentationData)
|
||||
shareController.completed = { peerIds in
|
||||
let _ = (context.account.postbox.transaction { transaction -> [Peer] in
|
||||
var peers: [Peer] = []
|
||||
@ -729,8 +738,9 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio
|
||||
ActionSheetButtonItem(title: presentationData.strings.InviteLink_DeleteLinkAlert_Action, color: .destructive, action: {
|
||||
dismissAction()
|
||||
|
||||
revokeLinkDisposable.set((context.engine.peers.deletePeerExportedInvitation(peerId: peerId, link: invite.link) |> deliverOnMainQueue).start(completed: {
|
||||
}))
|
||||
if let inviteLink = invite.link {
|
||||
revokeLinkDisposable.set((context.engine.peers.deletePeerExportedInvitation(peerId: peerId, link: inviteLink) |> deliverOnMainQueue).start())
|
||||
}
|
||||
|
||||
revokedInvitesContext.remove(invite)
|
||||
})
|
||||
@ -763,11 +773,13 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio
|
||||
ActionSheetButtonItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeLink, color: .destructive, action: {
|
||||
dismissAction()
|
||||
|
||||
revokeLinkDisposable.set((context.engine.peers.revokePeerExportedInvitation(peerId: peerId, link: invite.link) |> deliverOnMainQueue).start(next: { result in
|
||||
if case let .replace(_, newInvite) = result {
|
||||
invitesContext.add(newInvite)
|
||||
}
|
||||
}))
|
||||
if let inviteLink = invite.link {
|
||||
revokeLinkDisposable.set((context.engine.peers.revokePeerExportedInvitation(peerId: peerId, link: inviteLink) |> deliverOnMainQueue).start(next: { result in
|
||||
if case let .replace(_, newInvite) = result {
|
||||
invitesContext.add(newInvite)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
invitesContext.remove(invite)
|
||||
revokedInvitesContext.add(invite.withUpdated(isRevoked: true))
|
||||
|
@ -416,7 +416,7 @@ public final class InviteLinkViewController: ViewController {
|
||||
self.controller = controller
|
||||
|
||||
self.importersContext = importersContext ?? context.engine.peers.peerInvitationImporters(peerId: peerId, subject: .invite(invite: invite, requested: false))
|
||||
if invite.requestApproval {
|
||||
if case let .link(_, _, _, requestApproval, _, _, _, _, _, _, _, _) = invite, requestApproval {
|
||||
self.requestsContext = context.engine.peers.peerInvitationImporters(peerId: peerId, subject: .invite(invite: invite, requested: true))
|
||||
} else {
|
||||
self.requestsContext = nil
|
||||
@ -483,7 +483,10 @@ public final class InviteLinkViewController: ViewController {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
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))
|
||||
guard let inviteLink = invite.link else {
|
||||
return
|
||||
}
|
||||
let shareController = ShareController(context: context, subject: .url(inviteLink))
|
||||
shareController.completed = { [weak self] peerIds in
|
||||
if let strongSelf = self {
|
||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in
|
||||
@ -569,8 +572,9 @@ public final class InviteLinkViewController: ViewController {
|
||||
dismissAction()
|
||||
self?.controller?.dismiss()
|
||||
|
||||
let _ = (context.engine.peers.deletePeerExportedInvitation(peerId: peerId, link: invite.link) |> deliverOnMainQueue).start(completed: {
|
||||
})
|
||||
if let inviteLink = invite.link {
|
||||
let _ = (context.engine.peers.deletePeerExportedInvitation(peerId: peerId, link: inviteLink) |> deliverOnMainQueue).start()
|
||||
}
|
||||
|
||||
self?.controller?.revokedInvitationsContext?.remove(invite)
|
||||
})
|
||||
@ -626,11 +630,13 @@ public final class InviteLinkViewController: ViewController {
|
||||
dismissAction()
|
||||
self?.controller?.dismiss()
|
||||
|
||||
let _ = (context.engine.peers.revokePeerExportedInvitation(peerId: peerId, link: invite.link) |> deliverOnMainQueue).start(next: { result in
|
||||
if case let .replace(_, newInvite) = result {
|
||||
self?.controller?.invitationsContext?.add(newInvite)
|
||||
}
|
||||
})
|
||||
if let inviteLink = invite.link {
|
||||
let _ = (context.engine.peers.revokePeerExportedInvitation(peerId: peerId, link: inviteLink) |> deliverOnMainQueue).start(next: { result in
|
||||
if case let .replace(_, newInvite) = result {
|
||||
self?.controller?.invitationsContext?.add(newInvite)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
self?.controller?.invitationsContext?.remove(invite)
|
||||
let revokedInvite = invite.withUpdated(isRevoked: true)
|
||||
@ -662,93 +668,98 @@ public final class InviteLinkViewController: ViewController {
|
||||
requestsState = .single(PeerInvitationImportersState.Empty)
|
||||
}
|
||||
|
||||
let creatorPeer = context.account.postbox.loadedPeerWithId(invite.adminId)
|
||||
self.disposable = (combineLatest(self.presentationDataPromise.get(), self.importersContext.state, requestsState, creatorPeer)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData, state, requestsState, creatorPeer in
|
||||
if let strongSelf = self {
|
||||
var entries: [InviteLinkViewEntry] = []
|
||||
|
||||
entries.append(.link(presentationData.theme, invite))
|
||||
entries.append(.creatorHeader(presentationData.theme, presentationData.strings.InviteLink_CreatedBy.uppercased()))
|
||||
entries.append(.creator(presentationData.theme, presentationData.dateTimeFormat, EnginePeer(creatorPeer), invite.date))
|
||||
|
||||
if !requestsState.importers.isEmpty || (state.isLoadingMore && requestsState.count > 0) {
|
||||
entries.append(.requestHeader(presentationData.theme, presentationData.strings.MemberRequests_PeopleRequested(Int32(requestsState.count)).uppercased(), "", false))
|
||||
}
|
||||
|
||||
var count: Int32
|
||||
var loading: Bool
|
||||
var index: Int32 = 0
|
||||
if requestsState.importers.isEmpty && requestsState.isLoadingMore {
|
||||
count = min(4, state.count)
|
||||
loading = true
|
||||
let fakeUser = TelegramUser(id: EnginePeer.Id(namespace: .max, id: EnginePeer.Id.Id._internalFromInt64Value(0)), accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
for i in 0 ..< count {
|
||||
entries.append(.request(Int32(i), presentationData.theme, presentationData.dateTimeFormat, EnginePeer.user(fakeUser), 0, true))
|
||||
if case let .link(_, _, _, _, _, adminId, date, _, _, usageLimit, _, _) = invite {
|
||||
self.disposable = (combineLatest(
|
||||
self.presentationDataPromise.get(),
|
||||
self.importersContext.state,
|
||||
requestsState,
|
||||
context.account.postbox.loadedPeerWithId(adminId)
|
||||
) |> deliverOnMainQueue).start(next: { [weak self] presentationData, state, requestsState, creatorPeer in
|
||||
if let strongSelf = self {
|
||||
var entries: [InviteLinkViewEntry] = []
|
||||
|
||||
entries.append(.link(presentationData.theme, invite))
|
||||
entries.append(.creatorHeader(presentationData.theme, presentationData.strings.InviteLink_CreatedBy.uppercased()))
|
||||
entries.append(.creator(presentationData.theme, presentationData.dateTimeFormat, EnginePeer(creatorPeer), date))
|
||||
|
||||
if !requestsState.importers.isEmpty || (state.isLoadingMore && requestsState.count > 0) {
|
||||
entries.append(.requestHeader(presentationData.theme, presentationData.strings.MemberRequests_PeopleRequested(Int32(requestsState.count)).uppercased(), "", false))
|
||||
}
|
||||
} else {
|
||||
count = min(4, Int32(requestsState.importers.count))
|
||||
loading = false
|
||||
for importer in requestsState.importers {
|
||||
if let peer = importer.peer.peer {
|
||||
entries.append(.request(index, presentationData.theme, presentationData.dateTimeFormat, EnginePeer(peer), importer.date, false))
|
||||
|
||||
var count: Int32
|
||||
var loading: Bool
|
||||
var index: Int32 = 0
|
||||
if requestsState.importers.isEmpty && requestsState.isLoadingMore {
|
||||
count = min(4, state.count)
|
||||
loading = true
|
||||
let fakeUser = TelegramUser(id: EnginePeer.Id(namespace: .max, id: EnginePeer.Id.Id._internalFromInt64Value(0)), accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
for i in 0 ..< count {
|
||||
entries.append(.request(Int32(i), presentationData.theme, presentationData.dateTimeFormat, EnginePeer.user(fakeUser), 0, true))
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
if !state.importers.isEmpty || (state.isLoadingMore && state.count > 0) {
|
||||
let subtitle: String
|
||||
let subtitleExpired: Bool
|
||||
if let usageLimit = invite.usageLimit {
|
||||
let remaining = max(0, usageLimit - state.count)
|
||||
subtitle = presentationData.strings.InviteLink_PeopleRemaining(remaining).uppercased()
|
||||
subtitleExpired = remaining <= 0
|
||||
} else {
|
||||
subtitle = ""
|
||||
subtitleExpired = false
|
||||
}
|
||||
|
||||
entries.append(.importerHeader(presentationData.theme, presentationData.strings.InviteLink_PeopleJoined(Int32(state.count)).uppercased(), subtitle, subtitleExpired))
|
||||
}
|
||||
|
||||
index = 0
|
||||
if state.importers.isEmpty && state.isLoadingMore {
|
||||
count = min(4, state.count)
|
||||
loading = true
|
||||
let fakeUser = TelegramUser(id: EnginePeer.Id(namespace: .max, id: EnginePeer.Id.Id._internalFromInt64Value(0)), accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
for i in 0 ..< count {
|
||||
entries.append(.importer(Int32(i), presentationData.theme, presentationData.dateTimeFormat, EnginePeer.user(fakeUser), 0, true))
|
||||
}
|
||||
} else {
|
||||
count = min(4, Int32(state.importers.count))
|
||||
loading = false
|
||||
for importer in state.importers {
|
||||
if let peer = importer.peer.peer {
|
||||
entries.append(.importer(index, presentationData.theme, presentationData.dateTimeFormat, EnginePeer(peer), importer.date, false))
|
||||
count = min(4, Int32(requestsState.importers.count))
|
||||
loading = false
|
||||
for importer in requestsState.importers {
|
||||
if let peer = importer.peer.peer {
|
||||
entries.append(.request(index, presentationData.theme, presentationData.dateTimeFormat, EnginePeer(peer), importer.date, false))
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
let previousCount = previousCount.swap(count)
|
||||
let previousLoading = previousLoading.swap(loading)
|
||||
|
||||
var animated = false
|
||||
var crossfade = false
|
||||
if let previousCount = previousCount, let previousLoading = previousLoading {
|
||||
if (previousCount == count || previousCount >= 4) && previousLoading && !loading {
|
||||
crossfade = true
|
||||
} else if previousCount < 4 && previousCount != count && !loading {
|
||||
animated = true
|
||||
|
||||
if !state.importers.isEmpty || (state.isLoadingMore && state.count > 0) {
|
||||
let subtitle: String
|
||||
let subtitleExpired: Bool
|
||||
if let usageLimit = usageLimit {
|
||||
let remaining = max(0, usageLimit - state.count)
|
||||
subtitle = presentationData.strings.InviteLink_PeopleRemaining(remaining).uppercased()
|
||||
subtitleExpired = remaining <= 0
|
||||
} else {
|
||||
subtitle = ""
|
||||
subtitleExpired = false
|
||||
}
|
||||
|
||||
entries.append(.importerHeader(presentationData.theme, presentationData.strings.InviteLink_PeopleJoined(Int32(state.count)).uppercased(), subtitle, subtitleExpired))
|
||||
}
|
||||
|
||||
index = 0
|
||||
if state.importers.isEmpty && state.isLoadingMore {
|
||||
count = min(4, state.count)
|
||||
loading = true
|
||||
let fakeUser = TelegramUser(id: EnginePeer.Id(namespace: .max, id: EnginePeer.Id.Id._internalFromInt64Value(0)), accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
for i in 0 ..< count {
|
||||
entries.append(.importer(Int32(i), presentationData.theme, presentationData.dateTimeFormat, EnginePeer.user(fakeUser), 0, true))
|
||||
}
|
||||
} else {
|
||||
count = min(4, Int32(state.importers.count))
|
||||
loading = false
|
||||
for importer in state.importers {
|
||||
if let peer = importer.peer.peer {
|
||||
entries.append(.importer(index, presentationData.theme, presentationData.dateTimeFormat, EnginePeer(peer), importer.date, false))
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
let previousCount = previousCount.swap(count)
|
||||
let previousLoading = previousLoading.swap(loading)
|
||||
|
||||
var animated = false
|
||||
var crossfade = false
|
||||
if let previousCount = previousCount, let previousLoading = previousLoading {
|
||||
if (previousCount == count || previousCount >= 4) && previousLoading && !loading {
|
||||
crossfade = true
|
||||
} else if previousCount < 4 && previousCount != count && !loading {
|
||||
animated = true
|
||||
}
|
||||
}
|
||||
let previousEntries = previousEntries.swap(entries)
|
||||
|
||||
let transition = preparedTransition(from: previousEntries ?? [], to: entries, isLoading: false, animated: animated, crossfade: crossfade, account: context.account, presentationData: presentationData, interaction: strongSelf.interaction!)
|
||||
strongSelf.enqueueTransition(transition)
|
||||
}
|
||||
let previousEntries = previousEntries.swap(entries)
|
||||
|
||||
let transition = preparedTransition(from: previousEntries ?? [], to: entries, isLoading: false, animated: animated, crossfade: crossfade, account: context.account, presentationData: presentationData, interaction: strongSelf.interaction!)
|
||||
strongSelf.enqueueTransition(transition)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
self.listNode.preloadPages = true
|
||||
self.listNode.stackFromBottom = true
|
||||
@ -940,43 +951,45 @@ public final class InviteLinkViewController: ViewController {
|
||||
transition.updateFrame(node: self.headerBackgroundNode, frame: CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: 68.0))
|
||||
|
||||
var titleText = self.presentationData.strings.InviteLink_InviteLink
|
||||
|
||||
var subtitleText = ""
|
||||
var subtitleColor = self.presentationData.theme.list.itemSecondaryTextColor
|
||||
if self.invite.isRevoked {
|
||||
subtitleText = self.presentationData.strings.InviteLink_Revoked
|
||||
} else if let usageLimit = self.invite.usageLimit, let count = self.invite.count, count >= usageLimit {
|
||||
subtitleText = self.presentationData.strings.InviteLink_UsageLimitReached
|
||||
subtitleColor = self.presentationData.theme.list.itemDestructiveColor
|
||||
} else if let expireDate = self.invite.expireDate {
|
||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
if currentTime >= expireDate {
|
||||
titleText = self.presentationData.strings.InviteLink_ExpiredLink
|
||||
subtitleText = self.presentationData.strings.InviteLink_ExpiredLinkStatus
|
||||
|
||||
if case let .link(_, title, _, _, isRevoked, _, _, _, expireDate, usageLimit, count, _) = self.invite {
|
||||
if isRevoked {
|
||||
subtitleText = self.presentationData.strings.InviteLink_Revoked
|
||||
} else if let usageLimit = usageLimit, let count = count, count >= usageLimit {
|
||||
subtitleText = self.presentationData.strings.InviteLink_UsageLimitReached
|
||||
subtitleColor = self.presentationData.theme.list.itemDestructiveColor
|
||||
self.countdownTimer?.invalidate()
|
||||
self.countdownTimer = nil
|
||||
} else {
|
||||
let elapsedTime = expireDate - currentTime
|
||||
if elapsedTime >= 86400 {
|
||||
subtitleText = self.presentationData.strings.InviteLink_ExpiresIn(scheduledTimeIntervalString(strings: self.presentationData.strings, value: elapsedTime)).string
|
||||
} else if let expireDate = expireDate {
|
||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
if currentTime >= expireDate {
|
||||
titleText = self.presentationData.strings.InviteLink_ExpiredLink
|
||||
subtitleText = self.presentationData.strings.InviteLink_ExpiredLinkStatus
|
||||
subtitleColor = self.presentationData.theme.list.itemDestructiveColor
|
||||
self.countdownTimer?.invalidate()
|
||||
self.countdownTimer = nil
|
||||
} else {
|
||||
subtitleText = self.presentationData.strings.InviteLink_ExpiresIn(textForTimeout(value: elapsedTime)).string
|
||||
if self.countdownTimer == nil {
|
||||
let countdownTimer = SwiftSignalKit.Timer(timeout: 1.0, repeat: true, completion: { [weak self] in
|
||||
if let strongSelf = self, let layout = strongSelf.validLayout {
|
||||
strongSelf.containerLayoutUpdated(layout, transition: .immediate)
|
||||
}
|
||||
}, queue: Queue.mainQueue())
|
||||
self.countdownTimer = countdownTimer
|
||||
countdownTimer.start()
|
||||
let elapsedTime = expireDate - currentTime
|
||||
if elapsedTime >= 86400 {
|
||||
subtitleText = self.presentationData.strings.InviteLink_ExpiresIn(scheduledTimeIntervalString(strings: self.presentationData.strings, value: elapsedTime)).string
|
||||
} else {
|
||||
subtitleText = self.presentationData.strings.InviteLink_ExpiresIn(textForTimeout(value: elapsedTime)).string
|
||||
if self.countdownTimer == nil {
|
||||
let countdownTimer = SwiftSignalKit.Timer(timeout: 1.0, repeat: true, completion: { [weak self] in
|
||||
if let strongSelf = self, let layout = strongSelf.validLayout {
|
||||
strongSelf.containerLayoutUpdated(layout, transition: .immediate)
|
||||
}
|
||||
}, queue: Queue.mainQueue())
|
||||
self.countdownTimer = countdownTimer
|
||||
countdownTimer.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let title = self.invite.title, !title.isEmpty {
|
||||
titleText = title
|
||||
if let title = title, !title.isEmpty {
|
||||
titleText = title
|
||||
}
|
||||
}
|
||||
|
||||
self.titleNode.attributedText = NSAttributedString(string: titleText, font: Font.bold(17.0), textColor: self.presentationData.theme.actionSheet.primaryTextColor)
|
||||
|
@ -9,21 +9,25 @@ import ShimmerEffect
|
||||
import TelegramCore
|
||||
|
||||
func invitationAvailability(_ invite: ExportedInvitation) -> CGFloat {
|
||||
if invite.isRevoked {
|
||||
return 0.0
|
||||
if case let .link(_, _, _, _, isRevoked, _, date, startDate, expireDate, usageLimit, count, _) = invite {
|
||||
if isRevoked {
|
||||
return 0.0
|
||||
}
|
||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
var availability: CGFloat = 1.0
|
||||
if let expireDate = expireDate {
|
||||
let startDate = startDate ?? date
|
||||
let fraction = CGFloat(expireDate - currentTime) / CGFloat(expireDate - startDate)
|
||||
availability = min(fraction, availability)
|
||||
}
|
||||
if let usageLimit = usageLimit, let count = count {
|
||||
let fraction = 1.0 - (CGFloat(count) / CGFloat(usageLimit))
|
||||
availability = min(fraction, availability)
|
||||
}
|
||||
return max(0.0, min(1.0, availability))
|
||||
} else {
|
||||
return 1.0
|
||||
}
|
||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
var availability: CGFloat = 1.0
|
||||
if let expireDate = invite.expireDate {
|
||||
let startDate = invite.startDate ?? invite.date
|
||||
let fraction = CGFloat(expireDate - currentTime) / CGFloat(expireDate - startDate)
|
||||
availability = min(fraction, availability)
|
||||
}
|
||||
if let usageLimit = invite.usageLimit, let count = invite.count {
|
||||
let fraction = 1.0 - (CGFloat(count) / CGFloat(usageLimit))
|
||||
availability = min(fraction, availability)
|
||||
}
|
||||
return max(0.0, min(1.0, availability))
|
||||
}
|
||||
|
||||
private enum ItemBackgroundColor: Equatable {
|
||||
@ -295,12 +299,12 @@ public class ItemListInviteLinkItemNode: ListViewItemNode, ItemListItemNode {
|
||||
let color: ItemBackgroundColor
|
||||
let nextColor: ItemBackgroundColor
|
||||
let transitionFraction: CGFloat
|
||||
if let invite = item.invite {
|
||||
if invite.isRevoked {
|
||||
if let invite = item.invite, case let .link(_, _, _, _, isRevoked, _, _, _, expireDate, usageLimit, _, _) = invite {
|
||||
if isRevoked {
|
||||
color = .gray
|
||||
nextColor = .gray
|
||||
transitionFraction = 0.0
|
||||
} else if invite.expireDate == nil && invite.usageLimit == nil {
|
||||
} else if expireDate == nil && usageLimit == nil {
|
||||
color = .blue
|
||||
nextColor = .blue
|
||||
transitionFraction = 0.0
|
||||
@ -336,22 +340,24 @@ public class ItemListInviteLinkItemNode: ListViewItemNode, ItemListItemNode {
|
||||
iconColor = item.presentationData.theme.list.mediaPlaceholderColor
|
||||
}
|
||||
|
||||
let inviteLink = item.invite?.link.replacingOccurrences(of: "https://", with: "") ?? ""
|
||||
let inviteLink = item.invite?.link?.replacingOccurrences(of: "https://", with: "") ?? ""
|
||||
var titleText = inviteLink
|
||||
if let title = item.invite?.title, !title.isEmpty {
|
||||
titleText = title
|
||||
}
|
||||
|
||||
var subtitleText: String = ""
|
||||
var timerValue: TimerNode.Value?
|
||||
if let invite = item.invite {
|
||||
let count = invite.count ?? 0
|
||||
let requestedCount = invite.requestedCount ?? 0
|
||||
|
||||
|
||||
if let invite = item.invite, case let .link(_, title, _, _, _, _, date, startDate, expireDate, usageLimit, count, requestedCount) = invite {
|
||||
if let title = title, !title.isEmpty {
|
||||
titleText = title
|
||||
}
|
||||
|
||||
let count = count ?? 0
|
||||
let requestedCount = requestedCount ?? 0
|
||||
|
||||
if count > 0 {
|
||||
subtitleText = item.presentationData.strings.InviteLink_PeopleJoinedShort(count)
|
||||
} else {
|
||||
if let usageLimit = invite.usageLimit, count == 0 && !availability.isZero {
|
||||
if let usageLimit = usageLimit, count == 0 && !availability.isZero {
|
||||
subtitleText = item.presentationData.strings.InviteLink_PeopleCanJoin(usageLimit)
|
||||
} else {
|
||||
if availability.isZero {
|
||||
@ -376,12 +382,12 @@ public class ItemListInviteLinkItemNode: ListViewItemNode, ItemListItemNode {
|
||||
subtitleText += item.presentationData.strings.InviteLink_Revoked
|
||||
} else {
|
||||
var isExpired = false
|
||||
if let expireDate = invite.expireDate, currentTime >= expireDate {
|
||||
if let expireDate = expireDate, currentTime >= expireDate {
|
||||
isExpired = true
|
||||
}
|
||||
var isFull = false
|
||||
|
||||
if let usageLimit = invite.usageLimit {
|
||||
if let usageLimit = usageLimit {
|
||||
if !isExpired {
|
||||
let remaining = usageLimit - count
|
||||
if remaining > 0 && remaining != usageLimit {
|
||||
@ -401,7 +407,7 @@ public class ItemListInviteLinkItemNode: ListViewItemNode, ItemListItemNode {
|
||||
}
|
||||
}
|
||||
}
|
||||
if let expireDate = invite.expireDate, !isFull {
|
||||
if let expireDate = expireDate, !isFull {
|
||||
if !isExpired {
|
||||
if !subtitleText.isEmpty {
|
||||
subtitleText += " • "
|
||||
@ -413,7 +419,7 @@ public class ItemListInviteLinkItemNode: ListViewItemNode, ItemListItemNode {
|
||||
subtitleText += item.presentationData.strings.InviteLink_ExpiresIn(textForTimeout(value: elapsedTime)).string
|
||||
}
|
||||
if timerValue == nil {
|
||||
timerValue = .timestamp(creation: invite.startDate ?? invite.date, deadline: expireDate)
|
||||
timerValue = .timestamp(creation: startDate ?? date, deadline: expireDate)
|
||||
}
|
||||
} else {
|
||||
if !subtitleText.isEmpty {
|
||||
|
@ -300,14 +300,14 @@ public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItem
|
||||
let titleColor: UIColor
|
||||
titleColor = item.presentationData.theme.list.itemInputField.primaryColor
|
||||
|
||||
let alignCentrally = !(item.invite?.link.contains("joinchat") ?? true)
|
||||
let alignCentrally = !(item.invite?.link?.contains("joinchat") ?? true)
|
||||
|
||||
let addressFont = Font.regular(!alignCentrally && params.width == 320 ? floor(item.presentationData.fontSize.itemListBaseFontSize * 15.0 / 17.0) : item.presentationData.fontSize.itemListBaseFontSize)
|
||||
let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize)
|
||||
|
||||
let constrainedWidth = alignCentrally ? params.width - leftInset - rightInset - 90.0 : params.width - leftInset - rightInset - 60.0
|
||||
|
||||
let (addressLayout, addressApply) = makeAddressLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.invite.flatMap({ $0.link.replacingOccurrences(of: "https://", with: "") }) ?? "", font: addressFont, textColor: titleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .middle, constrainedSize: CGSize(width: constrainedWidth, 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: addressFont, textColor: titleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .middle, constrainedSize: CGSize(width: constrainedWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let subtitle: String
|
||||
let subtitleColor: UIColor
|
||||
|
@ -26,6 +26,7 @@ swift_library(
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
"//submodules/AnimationUI:AnimationUI",
|
||||
"//submodules/ShimmerEffect:ShimmerEffect",
|
||||
"//submodules/ManagedAnimationNode:ManagedAnimationNode",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -2,12 +2,12 @@ import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import AnimationUI
|
||||
import ManagedAnimationNode
|
||||
|
||||
public enum ItemListRevealOptionIcon: Equatable {
|
||||
case none
|
||||
case image(image: UIImage)
|
||||
case animation(animation: String, scale: CGFloat, offset: CGFloat, keysToColor: [String]?, flip: Bool)
|
||||
case animation(animation: String, scale: CGFloat, offset: CGFloat, replaceColors: [UInt32]?, flip: Bool)
|
||||
|
||||
public static func ==(lhs: ItemListRevealOptionIcon, rhs: ItemListRevealOptionIcon) -> Bool {
|
||||
switch lhs {
|
||||
@ -81,7 +81,8 @@ private final class ItemListRevealOptionNode: ASDisplayNode {
|
||||
private let highlightNode: ASDisplayNode
|
||||
private let titleNode: ASTextNode
|
||||
private let iconNode: ASImageNode?
|
||||
private let animationNode: AnimationNode?
|
||||
private let animationNode: SimpleAnimationNode?
|
||||
|
||||
private var animationNodeOffset: CGFloat = 0.0
|
||||
private var animationNodeFlip = false
|
||||
var alignment: ItemListRevealOptionAlignment?
|
||||
@ -101,15 +102,15 @@ private final class ItemListRevealOptionNode: ASDisplayNode {
|
||||
self.iconNode = iconNode
|
||||
self.animationNode = nil
|
||||
|
||||
case let .animation(animation, scale, offset, keysToColor, flip):
|
||||
case let .animation(animation, _, offset, replaceColors, flip):
|
||||
self.iconNode = nil
|
||||
var colors: [String: UIColor] = [:]
|
||||
if let keysToColor = keysToColor {
|
||||
for key in keysToColor {
|
||||
colors[key] = color
|
||||
var colors: [UInt32: UInt32] = [:]
|
||||
if let replaceColors = replaceColors {
|
||||
for colorToReplace in replaceColors {
|
||||
colors[colorToReplace] = color.rgb
|
||||
}
|
||||
}
|
||||
self.animationNode = AnimationNode(animation: animation, colors: colors, scale: scale)
|
||||
self.animationNode = SimpleAnimationNode(animationName: animation, replaceColors: colors, size: CGSize(width: 79.0, height: 79.0), playOnce: true)
|
||||
if flip {
|
||||
self.animationNode!.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
|
||||
}
|
||||
@ -192,7 +193,8 @@ private final class ItemListRevealOptionNode: ASDisplayNode {
|
||||
contentRect.origin.x = extendedWidth - contentRect.width
|
||||
}
|
||||
|
||||
if let animationNode = self.animationNode, let imageSize = animationNode.preferredSize() {
|
||||
if let animationNode = self.animationNode {
|
||||
let imageSize = animationNode.size
|
||||
let iconOffset: CGFloat = -2.0 + self.animationNodeOffset
|
||||
let titleIconSpacing: CGFloat = 11.0
|
||||
let iconFrame = CGRect(origin: CGPoint(x: contentRect.minX + floor((baseSize.width - imageSize.width + sideInset) / 2.0), y: contentRect.midY - imageSize.height / 2.0 + iconOffset), size: imageSize)
|
||||
|
@ -46,7 +46,7 @@ public final class ManagedAnimationState {
|
||||
} else if let unpackedData = TGGUnzipData(data, 5 * 1024 * 1024) {
|
||||
data = unpackedData
|
||||
}
|
||||
guard let instance = LottieInstance(data: data, fitzModifier: .none, cacheKey: item.source.cacheKey) else {
|
||||
guard let instance = LottieInstance(data: data, fitzModifier: .none, colorReplacements: item.replaceColors, cacheKey: item.source.cacheKey) else {
|
||||
return nil
|
||||
}
|
||||
resolvedInstance = instance
|
||||
@ -123,13 +123,15 @@ public enum ManagedAnimationSource: Equatable {
|
||||
|
||||
public struct ManagedAnimationItem {
|
||||
public let source: ManagedAnimationSource
|
||||
public let replaceColors: [UInt32: UInt32]?
|
||||
public var frames: ManagedAnimationFrameRange?
|
||||
public var duration: Double?
|
||||
public var loop: Bool
|
||||
var callbacks: [(Int, () -> Void)]
|
||||
|
||||
public init(source: ManagedAnimationSource, frames: ManagedAnimationFrameRange? = nil, duration: Double? = nil, loop: Bool = false, callbacks: [(Int, () -> Void)] = []) {
|
||||
public init(source: ManagedAnimationSource, replaceColors: [UInt32: UInt32]? = nil, frames: ManagedAnimationFrameRange? = nil, duration: Double? = nil, loop: Bool = false, callbacks: [(Int, () -> Void)] = []) {
|
||||
self.source = source
|
||||
self.replaceColors = replaceColors
|
||||
self.frames = frames
|
||||
self.duration = duration
|
||||
self.loop = loop
|
||||
@ -316,3 +318,35 @@ open class ManagedAnimationNode: ASDisplayNode {
|
||||
self.imageNode.position = CGPoint(x: self.bounds.width / 2.0, y: self.bounds.height / 2.0)
|
||||
}
|
||||
}
|
||||
|
||||
public final class SimpleAnimationNode: ManagedAnimationNode {
|
||||
private let stillItem: ManagedAnimationItem
|
||||
private let animationItem: ManagedAnimationItem
|
||||
|
||||
public let size: CGSize
|
||||
private let playOnce: Bool
|
||||
public private(set) var didPlay = false
|
||||
|
||||
public init(animationName: String, replaceColors: [UInt32: UInt32]? = nil, size: CGSize, playOnce: Bool = false) {
|
||||
self.size = size
|
||||
self.playOnce = playOnce
|
||||
self.stillItem = ManagedAnimationItem(source: .local(animationName), replaceColors: replaceColors, frames: .range(startFrame: 0, endFrame: 0), duration: 0.01)
|
||||
self.animationItem = ManagedAnimationItem(source: .local(animationName), replaceColors: replaceColors)
|
||||
|
||||
super.init(size: size)
|
||||
|
||||
self.trackTo(item: self.stillItem)
|
||||
}
|
||||
|
||||
public func play() {
|
||||
if !self.playOnce || !self.didPlay {
|
||||
self.didPlay = true
|
||||
self.trackTo(item: self.animationItem)
|
||||
}
|
||||
}
|
||||
|
||||
public func reset() {
|
||||
self.didPlay = false
|
||||
self.trackTo(item: self.stillItem)
|
||||
}
|
||||
}
|
||||
|
@ -36,8 +36,10 @@ private final class ChannelVisibilityControllerArguments {
|
||||
let manageInviteLinks: () -> Void
|
||||
let openLink: (ExportedInvitation) -> Void
|
||||
let toggleForwarding: (Bool) -> Void
|
||||
let updateJoinToSend: (CurrentChannelJoinToSend) -> Void
|
||||
let toggleApproveMembers: (Bool) -> Void
|
||||
|
||||
init(context: AccountContext, updateCurrentType: @escaping (CurrentChannelType) -> Void, updatePublicLinkText: @escaping (String?, String) -> Void, scrollToPublicLinkText: @escaping () -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, revokePeerId: @escaping (PeerId) -> Void, copyLink: @escaping (ExportedInvitation) -> Void, shareLink: @escaping (ExportedInvitation) -> Void, linkContextAction: @escaping (ASDisplayNode, ContextGesture?) -> Void, manageInviteLinks: @escaping () -> Void, openLink: @escaping (ExportedInvitation) -> Void, toggleForwarding: @escaping (Bool) -> Void) {
|
||||
init(context: AccountContext, updateCurrentType: @escaping (CurrentChannelType) -> Void, updatePublicLinkText: @escaping (String?, String) -> Void, scrollToPublicLinkText: @escaping () -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, revokePeerId: @escaping (PeerId) -> Void, copyLink: @escaping (ExportedInvitation) -> Void, shareLink: @escaping (ExportedInvitation) -> Void, linkContextAction: @escaping (ASDisplayNode, ContextGesture?) -> Void, manageInviteLinks: @escaping () -> Void, openLink: @escaping (ExportedInvitation) -> Void, toggleForwarding: @escaping (Bool) -> Void, updateJoinToSend: @escaping (CurrentChannelJoinToSend) -> Void, toggleApproveMembers: @escaping (Bool) -> Void) {
|
||||
self.context = context
|
||||
self.updateCurrentType = updateCurrentType
|
||||
self.updatePublicLinkText = updatePublicLinkText
|
||||
@ -50,6 +52,8 @@ private final class ChannelVisibilityControllerArguments {
|
||||
self.manageInviteLinks = manageInviteLinks
|
||||
self.openLink = openLink
|
||||
self.toggleForwarding = toggleForwarding
|
||||
self.updateJoinToSend = updateJoinToSend
|
||||
self.toggleApproveMembers = toggleApproveMembers
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,6 +61,8 @@ private enum ChannelVisibilitySection: Int32 {
|
||||
case type
|
||||
case link
|
||||
case linkActions
|
||||
case joinToSend
|
||||
case approveMembers
|
||||
case forwarding
|
||||
}
|
||||
|
||||
@ -94,6 +100,13 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
||||
case existingLinksInfo(PresentationTheme, String)
|
||||
case existingLinkPeerItem(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, Peer, ItemListPeerItemEditing, Bool)
|
||||
|
||||
case joinToSendHeader(PresentationTheme, String)
|
||||
case joinToSendEveryone(PresentationTheme, String, Bool)
|
||||
case joinToSendMembers(PresentationTheme, String, Bool)
|
||||
|
||||
case approveMembers(PresentationTheme, String, Bool)
|
||||
case approveMembersInfo(PresentationTheme, String)
|
||||
|
||||
case forwardingHeader(PresentationTheme, String)
|
||||
case forwardingDisabled(PresentationTheme, String, Bool)
|
||||
case forwardingInfo(PresentationTheme, String)
|
||||
@ -108,6 +121,10 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
||||
return ChannelVisibilitySection.linkActions.rawValue
|
||||
case .existingLinksInfo, .existingLinkPeerItem:
|
||||
return ChannelVisibilitySection.link.rawValue
|
||||
case .joinToSendHeader, .joinToSendEveryone, .joinToSendMembers:
|
||||
return ChannelVisibilitySection.joinToSend.rawValue
|
||||
case .approveMembers, .approveMembersInfo:
|
||||
return ChannelVisibilitySection.approveMembers.rawValue
|
||||
case .forwardingHeader, .forwardingDisabled, .forwardingInfo:
|
||||
return ChannelVisibilitySection.forwarding.rawValue
|
||||
}
|
||||
@ -147,12 +164,22 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
||||
return 1000
|
||||
case .privateLinkManageInfo:
|
||||
return 1001
|
||||
case .forwardingHeader:
|
||||
case .joinToSendHeader:
|
||||
return 1002
|
||||
case .forwardingDisabled:
|
||||
case .joinToSendEveryone:
|
||||
return 1003
|
||||
case .forwardingInfo:
|
||||
case .joinToSendMembers:
|
||||
return 1004
|
||||
case .approveMembers:
|
||||
return 1005
|
||||
case .approveMembersInfo:
|
||||
return 1006
|
||||
case .forwardingHeader:
|
||||
return 1007
|
||||
case .forwardingDisabled:
|
||||
return 1008
|
||||
case .forwardingInfo:
|
||||
return 1009
|
||||
}
|
||||
}
|
||||
|
||||
@ -278,6 +305,36 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .joinToSendHeader(lhsTheme, lhsText):
|
||||
if case let .joinToSendHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .joinToSendEveryone(lhsTheme, lhsText, lhsValue):
|
||||
if case let .joinToSendEveryone(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .joinToSendMembers(lhsTheme, lhsText, lhsValue):
|
||||
if case let .joinToSendMembers(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .approveMembers(lhsTheme, lhsText, lhsValue):
|
||||
if case let .approveMembers(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .approveMembersInfo(lhsTheme, lhsText):
|
||||
if case let .approveMembersInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .forwardingHeader(lhsTheme, lhsText):
|
||||
if case let .forwardingHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
@ -393,6 +450,22 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
|
||||
}, removePeer: { peerId in
|
||||
arguments.revokePeerId(peerId)
|
||||
})
|
||||
case let .joinToSendHeader(_, title):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
|
||||
case let .joinToSendEveryone(_, text, selected):
|
||||
return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
||||
arguments.updateJoinToSend(.everyone)
|
||||
})
|
||||
case let .joinToSendMembers(_, text, selected):
|
||||
return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
||||
arguments.updateJoinToSend(.members)
|
||||
})
|
||||
case let .approveMembers(_, text, selected):
|
||||
return ItemListSwitchItem(presentationData: presentationData, title: text, value: selected, sectionId: self.section, style: .blocks, updated: { value in
|
||||
arguments.toggleApproveMembers(value)
|
||||
})
|
||||
case let .approveMembersInfo(_, text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||
case let .forwardingHeader(_, title):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
|
||||
case let .forwardingDisabled(_, text, selected):
|
||||
@ -415,6 +488,11 @@ private enum CurrentChannelLocation: Equatable {
|
||||
case location(PeerGeoLocation)
|
||||
}
|
||||
|
||||
private enum CurrentChannelJoinToSend {
|
||||
case everyone
|
||||
case members
|
||||
}
|
||||
|
||||
private struct ChannelVisibilityControllerState: Equatable {
|
||||
let selectedType: CurrentChannelType?
|
||||
let editingPublicLinkText: String?
|
||||
@ -424,6 +502,8 @@ private struct ChannelVisibilityControllerState: Equatable {
|
||||
let revokingPeerId: PeerId?
|
||||
let revokingPrivateLink: Bool
|
||||
let forwardingEnabled: Bool?
|
||||
let joinToSend: CurrentChannelJoinToSend?
|
||||
let approveMembers: Bool?
|
||||
|
||||
init() {
|
||||
self.selectedType = nil
|
||||
@ -434,9 +514,11 @@ private struct ChannelVisibilityControllerState: Equatable {
|
||||
self.revokingPeerId = nil
|
||||
self.revokingPrivateLink = false
|
||||
self.forwardingEnabled = nil
|
||||
self.joinToSend = nil
|
||||
self.approveMembers = nil
|
||||
}
|
||||
|
||||
init(selectedType: CurrentChannelType?, editingPublicLinkText: String?, addressNameValidationStatus: AddressNameValidationStatus?, updatingAddressName: Bool, revealedRevokePeerId: PeerId?, revokingPeerId: PeerId?, revokingPrivateLink: Bool, forwardingEnabled: Bool?) {
|
||||
init(selectedType: CurrentChannelType?, editingPublicLinkText: String?, addressNameValidationStatus: AddressNameValidationStatus?, updatingAddressName: Bool, revealedRevokePeerId: PeerId?, revokingPeerId: PeerId?, revokingPrivateLink: Bool, forwardingEnabled: Bool?, joinToSend: CurrentChannelJoinToSend?, approveMembers: Bool?) {
|
||||
self.selectedType = selectedType
|
||||
self.editingPublicLinkText = editingPublicLinkText
|
||||
self.addressNameValidationStatus = addressNameValidationStatus
|
||||
@ -445,6 +527,8 @@ private struct ChannelVisibilityControllerState: Equatable {
|
||||
self.revokingPeerId = revokingPeerId
|
||||
self.revokingPrivateLink = revokingPrivateLink
|
||||
self.forwardingEnabled = forwardingEnabled
|
||||
self.joinToSend = joinToSend
|
||||
self.approveMembers = approveMembers
|
||||
}
|
||||
|
||||
static func ==(lhs: ChannelVisibilityControllerState, rhs: ChannelVisibilityControllerState) -> Bool {
|
||||
@ -472,39 +556,53 @@ private struct ChannelVisibilityControllerState: Equatable {
|
||||
if lhs.forwardingEnabled != rhs.forwardingEnabled {
|
||||
return false
|
||||
}
|
||||
if lhs.joinToSend != rhs.joinToSend {
|
||||
return false
|
||||
}
|
||||
if lhs.approveMembers != rhs.approveMembers {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func withUpdatedSelectedType(_ selectedType: CurrentChannelType?) -> ChannelVisibilityControllerState {
|
||||
return ChannelVisibilityControllerState(selectedType: selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: self.updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, forwardingEnabled: self.forwardingEnabled)
|
||||
return ChannelVisibilityControllerState(selectedType: selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: self.updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, forwardingEnabled: self.forwardingEnabled, joinToSend: self.joinToSend, approveMembers: self.approveMembers)
|
||||
}
|
||||
|
||||
func withUpdatedEditingPublicLinkText(_ editingPublicLinkText: String?) -> ChannelVisibilityControllerState {
|
||||
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: self.updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, forwardingEnabled: self.forwardingEnabled)
|
||||
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: self.updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, forwardingEnabled: self.forwardingEnabled, joinToSend: self.joinToSend, approveMembers: self.approveMembers)
|
||||
}
|
||||
|
||||
func withUpdatedAddressNameValidationStatus(_ addressNameValidationStatus: AddressNameValidationStatus?) -> ChannelVisibilityControllerState {
|
||||
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: addressNameValidationStatus, updatingAddressName: self.updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, forwardingEnabled: self.forwardingEnabled)
|
||||
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: addressNameValidationStatus, updatingAddressName: self.updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, forwardingEnabled: self.forwardingEnabled, joinToSend: self.joinToSend, approveMembers: self.approveMembers)
|
||||
}
|
||||
|
||||
func withUpdatedUpdatingAddressName(_ updatingAddressName: Bool) -> ChannelVisibilityControllerState {
|
||||
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, forwardingEnabled: self.forwardingEnabled)
|
||||
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, forwardingEnabled: self.forwardingEnabled, joinToSend: self.joinToSend, approveMembers: self.approveMembers)
|
||||
}
|
||||
|
||||
func withUpdatedRevealedRevokePeerId(_ revealedRevokePeerId: PeerId?) -> ChannelVisibilityControllerState {
|
||||
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, forwardingEnabled: self.forwardingEnabled)
|
||||
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, forwardingEnabled: self.forwardingEnabled, joinToSend: self.joinToSend, approveMembers: self.approveMembers)
|
||||
}
|
||||
|
||||
func withUpdatedRevokingPeerId(_ revokingPeerId: PeerId?) -> ChannelVisibilityControllerState {
|
||||
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, forwardingEnabled: self.forwardingEnabled)
|
||||
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, forwardingEnabled: self.forwardingEnabled, joinToSend: self.joinToSend, approveMembers: self.approveMembers)
|
||||
}
|
||||
|
||||
func withUpdatedRevokingPrivateLink(_ revokingPrivateLink: Bool) -> ChannelVisibilityControllerState {
|
||||
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: revokingPrivateLink, forwardingEnabled: self.forwardingEnabled)
|
||||
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: revokingPrivateLink, forwardingEnabled: self.forwardingEnabled, joinToSend: self.joinToSend, approveMembers: self.approveMembers)
|
||||
}
|
||||
|
||||
func withUpdatedForwardingEnabled(_ forwardingEnabled: Bool) -> ChannelVisibilityControllerState {
|
||||
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, forwardingEnabled: forwardingEnabled)
|
||||
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, forwardingEnabled: forwardingEnabled, joinToSend: self.joinToSend, approveMembers: self.approveMembers)
|
||||
}
|
||||
|
||||
func withUpdatedJoinToSend(_ joinToSend: CurrentChannelJoinToSend?) -> ChannelVisibilityControllerState {
|
||||
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, forwardingEnabled: self.forwardingEnabled, joinToSend: joinToSend, approveMembers: self.approveMembers)
|
||||
}
|
||||
|
||||
func withUpdatedApproveMembers(_ approveMembers: Bool) -> ChannelVisibilityControllerState {
|
||||
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, forwardingEnabled: self.forwardingEnabled, joinToSend: self.joinToSend, approveMembers: approveMembers)
|
||||
}
|
||||
}
|
||||
|
||||
@ -536,6 +634,28 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
||||
}
|
||||
}
|
||||
|
||||
let joinToSend: CurrentChannelJoinToSend
|
||||
if let current = state.joinToSend {
|
||||
joinToSend = current
|
||||
} else {
|
||||
if peer.flags.contains(.joinToSend) {
|
||||
joinToSend = .members
|
||||
} else {
|
||||
joinToSend = .everyone
|
||||
}
|
||||
}
|
||||
|
||||
let approveMembers: Bool
|
||||
if let enabled = state.approveMembers {
|
||||
approveMembers = enabled
|
||||
} else {
|
||||
if peer.flags.contains(.requestToJoin) {
|
||||
approveMembers = true
|
||||
} else {
|
||||
approveMembers = false
|
||||
}
|
||||
}
|
||||
|
||||
let forwardingEnabled: Bool
|
||||
if let enabled = state.forwardingEnabled {
|
||||
forwardingEnabled = enabled
|
||||
@ -696,11 +816,17 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
||||
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
|
||||
}
|
||||
}
|
||||
|
||||
entries.append(.joinToSendHeader(presentationData.theme, presentationData.strings.Group_Setup_WhoCanSendMessages_Title.uppercased()))
|
||||
entries.append(.joinToSendEveryone(presentationData.theme, presentationData.strings.Group_Setup_WhoCanSendMessages_Everyone, joinToSend == .everyone))
|
||||
entries.append(.joinToSendMembers(presentationData.theme, presentationData.strings.Group_Setup_WhoCanSendMessages_OnlyMembers, joinToSend == .members))
|
||||
|
||||
entries.append(.approveMembers(presentationData.theme, presentationData.strings.Group_Setup_ApproveNewMembers, approveMembers))
|
||||
entries.append(.approveMembersInfo(presentationData.theme, presentationData.strings.Group_Setup_ApproveNewMembersInfo))
|
||||
|
||||
entries.append(.forwardingHeader(presentationData.theme, isGroup ? presentationData.strings.Group_Setup_ForwardingGroupTitle.uppercased() : presentationData.strings.Group_Setup_ForwardingChannelTitle.uppercased()))
|
||||
entries.append(.forwardingDisabled(presentationData.theme, presentationData.strings.Group_Setup_ForwardingDisabled, !forwardingEnabled))
|
||||
entries.append(.forwardingInfo(presentationData.theme, forwardingEnabled ? (isGroup ? presentationData.strings.Group_Setup_ForwardingGroupInfo : presentationData.strings.Group_Setup_ForwardingChannelInfo) : (isGroup ? presentationData.strings.Group_Setup_ForwardingGroupInfoDisabled : presentationData.strings.Group_Setup_ForwardingChannelInfoDisabled)))
|
||||
|
||||
} else if let peer = view.peers[view.peerId] as? TelegramGroup {
|
||||
switch mode {
|
||||
case .privateLink:
|
||||
@ -816,7 +942,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let forwardingEnabled: Bool
|
||||
if let enabled = state.forwardingEnabled {
|
||||
forwardingEnabled = enabled
|
||||
@ -1009,7 +1135,10 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
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)
|
||||
}, shareLink: { invite in
|
||||
let shareController = ShareController(context: context, subject: .url(invite.link), updatedPresentationData: updatedPresentationData)
|
||||
guard let inviteLink = invite.link else {
|
||||
return
|
||||
}
|
||||
let shareController = ShareController(context: context, subject: .url(inviteLink), updatedPresentationData: updatedPresentationData)
|
||||
shareController.actionCompleted = {
|
||||
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)
|
||||
@ -1151,6 +1280,14 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
updateState { state in
|
||||
return state.withUpdatedForwardingEnabled(value)
|
||||
}
|
||||
}, updateJoinToSend: { value in
|
||||
updateState { state in
|
||||
return state.withUpdatedJoinToSend(value)
|
||||
}
|
||||
}, toggleApproveMembers: { value in
|
||||
updateState { state in
|
||||
return state.withUpdatedApproveMembers(value)
|
||||
}
|
||||
})
|
||||
|
||||
let peerView = context.account.viewTracker.peerView(peerId)
|
||||
@ -1220,6 +1357,14 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
toggleCopyProtectionDisposable.set(context.engine.peers.toggleMessageCopyProtection(peerId: peerId, enabled: !updatedCopyProtection).start())
|
||||
}
|
||||
|
||||
if let updatedJoinToSend = state.joinToSend {
|
||||
toggleCopyProtectionDisposable.set(context.engine.peers.toggleChannelJoinToSend(peerId: peerId, enabled: updatedJoinToSend == .members).start())
|
||||
}
|
||||
|
||||
if let updatedApproveMembers = state.approveMembers {
|
||||
toggleCopyProtectionDisposable.set(context.engine.peers.toggleChannelJoinRequest(peerId: peerId, enabled: updatedApproveMembers).start())
|
||||
}
|
||||
|
||||
if let updatedAddressNameValue = updatedAddressNameValue {
|
||||
let invokeAction: () -> Void = {
|
||||
updateState { state in
|
||||
|
@ -44,7 +44,7 @@ public final class QrCodeScreen: ViewController {
|
||||
case let .peer(peer):
|
||||
return "https://t.me/\(peer.addressName ?? "")"
|
||||
case let .invite(invite, _):
|
||||
return invite.link
|
||||
return invite.link ?? ""
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -475,6 +475,12 @@ public final class ShareController: ViewController {
|
||||
})
|
||||
|
||||
self.switchToAccount(account: currentAccount, animateIn: false)
|
||||
|
||||
if self.fromForeignApp {
|
||||
if let application = UIApplication.value(forKeyPath: #keyPath(UIApplication.shared)) as? UIApplication {
|
||||
application.isIdleTimerDisabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
@ -485,6 +491,12 @@ public final class ShareController: ViewController {
|
||||
self.peersDisposable.dispose()
|
||||
self.readyDisposable.dispose()
|
||||
self.accountActiveDisposable.dispose()
|
||||
|
||||
if self.fromForeignApp {
|
||||
if let application = UIApplication.value(forKeyPath: #keyPath(UIApplication.shared)) as? UIApplication {
|
||||
application.isIdleTimerDisabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
|
@ -11,6 +11,7 @@ swift_library(
|
||||
],
|
||||
deps = [
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -1,5 +1,6 @@
|
||||
import Foundation
|
||||
import AVFoundation
|
||||
import AccountContext
|
||||
|
||||
// Incuding at least one Objective-C class in a swift file ensures that it doesn't get stripped by the linker
|
||||
private final class LinkHelperClass: NSObject {
|
||||
@ -38,10 +39,11 @@ public func supportedSpeakLanguages() -> Set<String> {
|
||||
return Set(languages)
|
||||
}
|
||||
|
||||
public func speakText(_ text: String) -> SpeechSynthesizerHolder? {
|
||||
public func speakText(context: AccountContext, text: String) -> SpeechSynthesizerHolder? {
|
||||
guard !text.isEmpty else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let speechSynthesizer = AVSpeechSynthesizer()
|
||||
let utterance = AVSpeechUtterance(string: text)
|
||||
if #available(iOS 11.0, *), let language = NSLinguisticTagger.dominantLanguage(for: text) {
|
||||
|
@ -30,7 +30,7 @@ public func fetchCompressedLottieFirstFrameAJpeg(data: Data, size: CGSize, fitzM
|
||||
|
||||
let decompressedData = TGGUnzipData(data, 8 * 1024 * 1024)
|
||||
if let decompressedData = decompressedData {
|
||||
if let player = LottieInstance(data: decompressedData, fitzModifier: fitzModifier?.lottieFitzModifier ?? .none, cacheKey: cacheKey) {
|
||||
if let player = LottieInstance(data: decompressedData, fitzModifier: fitzModifier?.lottieFitzModifier ?? .none, colorReplacements: nil, cacheKey: cacheKey) {
|
||||
if cancelled.with({ $0 }) {
|
||||
return
|
||||
}
|
||||
@ -128,7 +128,7 @@ public func cacheAnimatedStickerFrames(data: Data, size: CGSize, fitzModifier: E
|
||||
|
||||
let decompressedData = TGGUnzipData(data, 8 * 1024 * 1024)
|
||||
if let decompressedData = decompressedData {
|
||||
if let player = LottieInstance(data: decompressedData, fitzModifier: fitzModifier?.lottieFitzModifier ?? .none, cacheKey: cacheKey) {
|
||||
if let player = LottieInstance(data: decompressedData, fitzModifier: fitzModifier?.lottieFitzModifier ?? .none, colorReplacements: nil, cacheKey: cacheKey) {
|
||||
let endFrame = Int(player.frameCount)
|
||||
|
||||
if cancelled.with({ $0 }) {
|
||||
|
@ -4,7 +4,6 @@ public enum Api {
|
||||
public enum auth {}
|
||||
public enum channels {}
|
||||
public enum contacts {}
|
||||
public enum feed {}
|
||||
public enum help {}
|
||||
public enum messages {}
|
||||
public enum payments {}
|
||||
@ -22,7 +21,6 @@ public enum Api {
|
||||
public enum bots {}
|
||||
public enum channels {}
|
||||
public enum contacts {}
|
||||
public enum feed {}
|
||||
public enum folders {}
|
||||
public enum help {}
|
||||
public enum langpack {}
|
||||
@ -70,7 +68,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1071145937] = { return Api.BotCommandScope.parse_botCommandScopePeerAdmins($0) }
|
||||
dict[169026035] = { return Api.BotCommandScope.parse_botCommandScopePeerUser($0) }
|
||||
dict[1011811544] = { return Api.BotCommandScope.parse_botCommandScopeUsers($0) }
|
||||
dict[-468280483] = { return Api.BotInfo.parse_botInfo($0) }
|
||||
dict[-863263529] = { return Api.BotInfo.parse_botInfo($0) }
|
||||
dict[1984755728] = { return Api.BotInlineMessage.parse_botInlineMessageMediaAuto($0) }
|
||||
dict[416402882] = { return Api.BotInlineMessage.parse_botInlineMessageMediaContact($0) }
|
||||
dict[85477117] = { return Api.BotInlineMessage.parse_botInlineMessageMediaGeo($0) }
|
||||
@ -200,8 +198,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-317144808] = { return Api.EncryptedMessage.parse_encryptedMessage($0) }
|
||||
dict[594758406] = { return Api.EncryptedMessage.parse_encryptedMessageService($0) }
|
||||
dict[179611673] = { return Api.ExportedChatInvite.parse_chatInviteExported($0) }
|
||||
dict[-317687113] = { return Api.ExportedChatInvite.parse_chatInvitePublicJoinRequests($0) }
|
||||
dict[1571494644] = { return Api.ExportedMessageLink.parse_exportedMessageLink($0) }
|
||||
dict[1348066419] = { return Api.FeedPosition.parse_feedPosition($0) }
|
||||
dict[1648543603] = { return Api.FileHash.parse_fileHash($0) }
|
||||
dict[-11252123] = { return Api.Folder.parse_folder($0) }
|
||||
dict[-373643672] = { return Api.FolderPeer.parse_folderPeer($0) }
|
||||
@ -791,7 +789,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1842450928] = { return Api.Update.parse_updateReadChannelInbox($0) }
|
||||
dict[-1218471511] = { return Api.Update.parse_updateReadChannelOutbox($0) }
|
||||
dict[1461528386] = { return Api.Update.parse_updateReadFeaturedStickers($0) }
|
||||
dict[1951948721] = { return Api.Update.parse_updateReadFeed($0) }
|
||||
dict[-1667805217] = { return Api.Update.parse_updateReadHistoryInbox($0) }
|
||||
dict[791617983] = { return Api.Update.parse_updateReadHistoryOutbox($0) }
|
||||
dict[1757493555] = { return Api.Update.parse_updateReadMessagesContents($0) }
|
||||
@ -900,8 +897,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1891070632] = { return Api.contacts.TopPeers.parse_topPeers($0) }
|
||||
dict[-1255369827] = { return Api.contacts.TopPeers.parse_topPeersDisabled($0) }
|
||||
dict[-567906571] = { return Api.contacts.TopPeers.parse_topPeersNotModified($0) }
|
||||
dict[-587770695] = { return Api.feed.FeedMessages.parse_feedMessages($0) }
|
||||
dict[-619039485] = { return Api.feed.FeedMessages.parse_feedMessagesNotModified($0) }
|
||||
dict[-860107216] = { return Api.help.AppUpdate.parse_appUpdate($0) }
|
||||
dict[-1000708810] = { return Api.help.AppUpdate.parse_noAppUpdate($0) }
|
||||
dict[-2016381538] = { return Api.help.CountriesList.parse_countriesList($0) }
|
||||
@ -1210,8 +1205,6 @@ public extension Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.ExportedMessageLink:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.FeedPosition:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.FileHash:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.Folder:
|
||||
@ -1624,8 +1617,6 @@ public extension Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.contacts.TopPeers:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.feed.FeedMessages:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.help.AppUpdate:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.help.CountriesList:
|
||||
|
@ -856,52 +856,62 @@ public extension Api {
|
||||
}
|
||||
public extension Api {
|
||||
enum BotInfo: TypeConstructorDescription {
|
||||
case botInfo(userId: Int64, description: String, commands: [Api.BotCommand], menuButton: Api.BotMenuButton)
|
||||
case botInfo(flags: Int32, userId: Int64?, description: String?, descriptionPhoto: Api.Photo?, commands: [Api.BotCommand]?, menuButton: Api.BotMenuButton?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .botInfo(let userId, let description, let commands, let menuButton):
|
||||
case .botInfo(let flags, let userId, let description, let descriptionPhoto, let commands, let menuButton):
|
||||
if boxed {
|
||||
buffer.appendInt32(-468280483)
|
||||
buffer.appendInt32(-863263529)
|
||||
}
|
||||
serializeInt64(userId, buffer: buffer, boxed: false)
|
||||
serializeString(description, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(commands.count))
|
||||
for item in commands {
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt64(userId!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 1) != 0 {serializeString(description!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 4) != 0 {descriptionPhoto!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 2) != 0 {buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(commands!.count))
|
||||
for item in commands! {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
menuButton.serialize(buffer, true)
|
||||
}}
|
||||
if Int(flags) & Int(1 << 3) != 0 {menuButton!.serialize(buffer, true)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .botInfo(let userId, let description, let commands, let menuButton):
|
||||
return ("botInfo", [("userId", String(describing: userId)), ("description", String(describing: description)), ("commands", String(describing: commands)), ("menuButton", String(describing: menuButton))])
|
||||
case .botInfo(let flags, let userId, let description, let descriptionPhoto, let commands, let menuButton):
|
||||
return ("botInfo", [("flags", String(describing: flags)), ("userId", String(describing: userId)), ("description", String(describing: description)), ("descriptionPhoto", String(describing: descriptionPhoto)), ("commands", String(describing: commands)), ("menuButton", String(describing: menuButton))])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_botInfo(_ reader: BufferReader) -> BotInfo? {
|
||||
var _1: Int64?
|
||||
_1 = reader.readInt64()
|
||||
var _2: String?
|
||||
_2 = parseString(reader)
|
||||
var _3: [Api.BotCommand]?
|
||||
if let _ = reader.readInt32() {
|
||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BotCommand.self)
|
||||
}
|
||||
var _4: Api.BotMenuButton?
|
||||
if let signature = reader.readInt32() {
|
||||
_4 = Api.parse(reader, signature: signature) as? Api.BotMenuButton
|
||||
}
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int64?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {_2 = reader.readInt64() }
|
||||
var _3: String?
|
||||
if Int(_1!) & Int(1 << 1) != 0 {_3 = parseString(reader) }
|
||||
var _4: Api.Photo?
|
||||
if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() {
|
||||
_4 = Api.parse(reader, signature: signature) as? Api.Photo
|
||||
} }
|
||||
var _5: [Api.BotCommand]?
|
||||
if Int(_1!) & Int(1 << 2) != 0 {if let _ = reader.readInt32() {
|
||||
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BotCommand.self)
|
||||
} }
|
||||
var _6: Api.BotMenuButton?
|
||||
if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() {
|
||||
_6 = Api.parse(reader, signature: signature) as? Api.BotMenuButton
|
||||
} }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 {
|
||||
return Api.BotInfo.botInfo(userId: _1!, description: _2!, commands: _3!, menuButton: _4!)
|
||||
let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil
|
||||
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 4) == 0) || _4 != nil
|
||||
let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil
|
||||
let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
|
||||
return Api.BotInfo.botInfo(flags: _1!, userId: _2, description: _3, descriptionPhoto: _4, commands: _5, menuButton: _6)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
@ -589,7 +589,6 @@ public extension Api {
|
||||
case updateReadChannelInbox(flags: Int32, folderId: Int32?, channelId: Int64, maxId: Int32, stillUnreadCount: Int32, pts: Int32)
|
||||
case updateReadChannelOutbox(channelId: Int64, maxId: Int32)
|
||||
case updateReadFeaturedStickers
|
||||
case updateReadFeed(flags: Int32, filterId: Int32, maxPosition: Api.FeedPosition, unreadCount: Int32?, unreadMutedCount: Int32?)
|
||||
case updateReadHistoryInbox(flags: Int32, folderId: Int32?, peer: Api.Peer, maxId: Int32, stillUnreadCount: Int32, pts: Int32, ptsCount: Int32)
|
||||
case updateReadHistoryOutbox(peer: Api.Peer, maxId: Int32, pts: Int32, ptsCount: Int32)
|
||||
case updateReadMessagesContents(messages: [Int32], pts: Int32, ptsCount: Int32)
|
||||
@ -1334,16 +1333,6 @@ public extension Api {
|
||||
buffer.appendInt32(1461528386)
|
||||
}
|
||||
|
||||
break
|
||||
case .updateReadFeed(let flags, let filterId, let maxPosition, let unreadCount, let unreadMutedCount):
|
||||
if boxed {
|
||||
buffer.appendInt32(1951948721)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt32(filterId, buffer: buffer, boxed: false)
|
||||
maxPosition.serialize(buffer, true)
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(unreadCount!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(unreadMutedCount!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
case .updateReadHistoryInbox(let flags, let folderId, let peer, let maxId, let stillUnreadCount, let pts, let ptsCount):
|
||||
if boxed {
|
||||
@ -1658,8 +1647,6 @@ public extension Api {
|
||||
return ("updateReadChannelOutbox", [("channelId", String(describing: channelId)), ("maxId", String(describing: maxId))])
|
||||
case .updateReadFeaturedStickers:
|
||||
return ("updateReadFeaturedStickers", [])
|
||||
case .updateReadFeed(let flags, let filterId, let maxPosition, let unreadCount, let unreadMutedCount):
|
||||
return ("updateReadFeed", [("flags", String(describing: flags)), ("filterId", String(describing: filterId)), ("maxPosition", String(describing: maxPosition)), ("unreadCount", String(describing: unreadCount)), ("unreadMutedCount", String(describing: unreadMutedCount))])
|
||||
case .updateReadHistoryInbox(let flags, let folderId, let peer, let maxId, let stillUnreadCount, let pts, let ptsCount):
|
||||
return ("updateReadHistoryInbox", [("flags", String(describing: flags)), ("folderId", String(describing: folderId)), ("peer", String(describing: peer)), ("maxId", String(describing: maxId)), ("stillUnreadCount", String(describing: stillUnreadCount)), ("pts", String(describing: pts)), ("ptsCount", String(describing: ptsCount))])
|
||||
case .updateReadHistoryOutbox(let peer, let maxId, let pts, let ptsCount):
|
||||
@ -3195,31 +3182,6 @@ public extension Api {
|
||||
public static func parse_updateReadFeaturedStickers(_ reader: BufferReader) -> Update? {
|
||||
return Api.Update.updateReadFeaturedStickers
|
||||
}
|
||||
public static func parse_updateReadFeed(_ reader: BufferReader) -> Update? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int32?
|
||||
_2 = reader.readInt32()
|
||||
var _3: Api.FeedPosition?
|
||||
if let signature = reader.readInt32() {
|
||||
_3 = Api.parse(reader, signature: signature) as? Api.FeedPosition
|
||||
}
|
||||
var _4: Int32?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {_4 = reader.readInt32() }
|
||||
var _5: Int32?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {_5 = reader.readInt32() }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
|
||||
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
||||
return Api.Update.updateReadFeed(flags: _1!, filterId: _2!, maxPosition: _3!, unreadCount: _4, unreadMutedCount: _5)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_updateReadHistoryInbox(_ reader: BufferReader) -> Update? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
|
@ -1104,102 +1104,6 @@ public extension Api.contacts {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.feed {
|
||||
enum FeedMessages: TypeConstructorDescription {
|
||||
case feedMessages(flags: Int32, maxPosition: Api.FeedPosition?, minPosition: Api.FeedPosition?, readMaxPosition: Api.FeedPosition?, messages: [Api.Message], chats: [Api.Chat], users: [Api.User])
|
||||
case feedMessagesNotModified
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .feedMessages(let flags, let maxPosition, let minPosition, let readMaxPosition, let messages, let chats, let users):
|
||||
if boxed {
|
||||
buffer.appendInt32(-587770695)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {maxPosition!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 1) != 0 {minPosition!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 2) != 0 {readMaxPosition!.serialize(buffer, true)}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(messages.count))
|
||||
for item in messages {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(chats.count))
|
||||
for item in chats {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(users.count))
|
||||
for item in users {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
case .feedMessagesNotModified:
|
||||
if boxed {
|
||||
buffer.appendInt32(-619039485)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .feedMessages(let flags, let maxPosition, let minPosition, let readMaxPosition, let messages, let chats, let users):
|
||||
return ("feedMessages", [("flags", String(describing: flags)), ("maxPosition", String(describing: maxPosition)), ("minPosition", String(describing: minPosition)), ("readMaxPosition", String(describing: readMaxPosition)), ("messages", String(describing: messages)), ("chats", String(describing: chats)), ("users", String(describing: users))])
|
||||
case .feedMessagesNotModified:
|
||||
return ("feedMessagesNotModified", [])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_feedMessages(_ reader: BufferReader) -> FeedMessages? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Api.FeedPosition?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
|
||||
_2 = Api.parse(reader, signature: signature) as? Api.FeedPosition
|
||||
} }
|
||||
var _3: Api.FeedPosition?
|
||||
if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() {
|
||||
_3 = Api.parse(reader, signature: signature) as? Api.FeedPosition
|
||||
} }
|
||||
var _4: Api.FeedPosition?
|
||||
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
|
||||
_4 = Api.parse(reader, signature: signature) as? Api.FeedPosition
|
||||
} }
|
||||
var _5: [Api.Message]?
|
||||
if let _ = reader.readInt32() {
|
||||
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
|
||||
}
|
||||
var _6: [Api.Chat]?
|
||||
if let _ = reader.readInt32() {
|
||||
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
|
||||
}
|
||||
var _7: [Api.User]?
|
||||
if let _ = reader.readInt32() {
|
||||
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil
|
||||
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
let _c6 = _6 != nil
|
||||
let _c7 = _7 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
|
||||
return Api.feed.FeedMessages.feedMessages(flags: _1!, maxPosition: _2, minPosition: _3, readMaxPosition: _4, messages: _5!, chats: _6!, users: _7!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_feedMessagesNotModified(_ reader: BufferReader) -> FeedMessages? {
|
||||
return Api.feed.FeedMessages.feedMessagesNotModified
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.help {
|
||||
enum AppUpdate: TypeConstructorDescription {
|
||||
case appUpdate(flags: Int32, id: Int32, version: String, text: String, entities: [Api.MessageEntity], document: Api.Document?, url: String?, sticker: Api.Document?)
|
||||
@ -1344,3 +1248,61 @@ public extension Api.help {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.help {
|
||||
enum Country: TypeConstructorDescription {
|
||||
case country(flags: Int32, iso2: String, defaultName: String, name: String?, countryCodes: [Api.help.CountryCode])
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .country(let flags, let iso2, let defaultName, let name, let countryCodes):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1014526429)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeString(iso2, buffer: buffer, boxed: false)
|
||||
serializeString(defaultName, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 1) != 0 {serializeString(name!, buffer: buffer, boxed: false)}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(countryCodes.count))
|
||||
for item in countryCodes {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .country(let flags, let iso2, let defaultName, let name, let countryCodes):
|
||||
return ("country", [("flags", String(describing: flags)), ("iso2", String(describing: iso2)), ("defaultName", String(describing: defaultName)), ("name", String(describing: name)), ("countryCodes", String(describing: countryCodes))])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_country(_ reader: BufferReader) -> Country? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: String?
|
||||
_2 = parseString(reader)
|
||||
var _3: String?
|
||||
_3 = parseString(reader)
|
||||
var _4: String?
|
||||
if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) }
|
||||
var _5: [Api.help.CountryCode]?
|
||||
if let _ = reader.readInt32() {
|
||||
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.help.CountryCode.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
||||
return Api.help.Country.country(flags: _1!, iso2: _2!, defaultName: _3!, name: _4, countryCodes: _5!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,61 +1,3 @@
|
||||
public extension Api.help {
|
||||
enum Country: TypeConstructorDescription {
|
||||
case country(flags: Int32, iso2: String, defaultName: String, name: String?, countryCodes: [Api.help.CountryCode])
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .country(let flags, let iso2, let defaultName, let name, let countryCodes):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1014526429)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeString(iso2, buffer: buffer, boxed: false)
|
||||
serializeString(defaultName, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 1) != 0 {serializeString(name!, buffer: buffer, boxed: false)}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(countryCodes.count))
|
||||
for item in countryCodes {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .country(let flags, let iso2, let defaultName, let name, let countryCodes):
|
||||
return ("country", [("flags", String(describing: flags)), ("iso2", String(describing: iso2)), ("defaultName", String(describing: defaultName)), ("name", String(describing: name)), ("countryCodes", String(describing: countryCodes))])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_country(_ reader: BufferReader) -> Country? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: String?
|
||||
_2 = parseString(reader)
|
||||
var _3: String?
|
||||
_3 = parseString(reader)
|
||||
var _4: String?
|
||||
if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) }
|
||||
var _5: [Api.help.CountryCode]?
|
||||
if let _ = reader.readInt32() {
|
||||
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.help.CountryCode.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
||||
return Api.help.Country.country(flags: _1!, iso2: _2!, defaultName: _3!, name: _4, countryCodes: _5!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.help {
|
||||
enum CountryCode: TypeConstructorDescription {
|
||||
case countryCode(flags: Int32, countryCode: String, prefixes: [String]?, patterns: [String]?)
|
||||
@ -1350,3 +1292,39 @@ public extension Api.messages {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum CheckedHistoryImportPeer: TypeConstructorDescription {
|
||||
case checkedHistoryImportPeer(confirmText: String)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .checkedHistoryImportPeer(let confirmText):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1571952873)
|
||||
}
|
||||
serializeString(confirmText, buffer: buffer, boxed: false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .checkedHistoryImportPeer(let confirmText):
|
||||
return ("checkedHistoryImportPeer", [("confirmText", String(describing: confirmText))])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_checkedHistoryImportPeer(_ reader: BufferReader) -> CheckedHistoryImportPeer? {
|
||||
var _1: String?
|
||||
_1 = parseString(reader)
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.messages.CheckedHistoryImportPeer.checkedHistoryImportPeer(confirmText: _1!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,39 +1,3 @@
|
||||
public extension Api.messages {
|
||||
enum CheckedHistoryImportPeer: TypeConstructorDescription {
|
||||
case checkedHistoryImportPeer(confirmText: String)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .checkedHistoryImportPeer(let confirmText):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1571952873)
|
||||
}
|
||||
serializeString(confirmText, buffer: buffer, boxed: false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .checkedHistoryImportPeer(let confirmText):
|
||||
return ("checkedHistoryImportPeer", [("confirmText", String(describing: confirmText))])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_checkedHistoryImportPeer(_ reader: BufferReader) -> CheckedHistoryImportPeer? {
|
||||
var _1: String?
|
||||
_1 = parseString(reader)
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.messages.CheckedHistoryImportPeer.checkedHistoryImportPeer(confirmText: _1!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum DhConfig: TypeConstructorDescription {
|
||||
case dhConfig(g: Int32, p: Buffer, version: Int32, random: Buffer)
|
||||
|
@ -2284,6 +2284,38 @@ public extension Api.functions.channels {
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.channels {
|
||||
static func toggleJoinRequest(channel: Api.InputChannel, enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(1277789622)
|
||||
channel.serialize(buffer, true)
|
||||
enabled.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "channels.toggleJoinRequest", parameters: [("channel", String(describing: channel)), ("enabled", String(describing: enabled))]), 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 extension Api.functions.channels {
|
||||
static func toggleJoinToSend(channel: Api.InputChannel, enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-456419968)
|
||||
channel.serialize(buffer, true)
|
||||
enabled.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "channels.toggleJoinToSend", parameters: [("channel", String(describing: channel)), ("enabled", String(describing: enabled))]), 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 extension Api.functions.channels {
|
||||
static func togglePreHistoryHidden(channel: Api.InputChannel, enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
@ -2704,44 +2736,6 @@ public extension Api.functions.contacts {
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.feed {
|
||||
static func getFeed(flags: Int32, filterId: Int32, offsetPosition: Api.FeedPosition?, addOffset: Int32, limit: Int32, maxPosition: Api.FeedPosition?, minPosition: Api.FeedPosition?, hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.feed.FeedMessages>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(2121717715)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt32(filterId, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {offsetPosition!.serialize(buffer, true)}
|
||||
serializeInt32(addOffset, buffer: buffer, boxed: false)
|
||||
serializeInt32(limit, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 1) != 0 {maxPosition!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 2) != 0 {minPosition!.serialize(buffer, true)}
|
||||
serializeInt64(hash, buffer: buffer, boxed: false)
|
||||
return (FunctionDescription(name: "feed.getFeed", parameters: [("flags", String(describing: flags)), ("filterId", String(describing: filterId)), ("offsetPosition", String(describing: offsetPosition)), ("addOffset", String(describing: addOffset)), ("limit", String(describing: limit)), ("maxPosition", String(describing: maxPosition)), ("minPosition", String(describing: minPosition)), ("hash", String(describing: hash))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.feed.FeedMessages? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.feed.FeedMessages?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.feed.FeedMessages
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.feed {
|
||||
static func readFeed(filterId: Int32, maxPosition: Api.FeedPosition) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-1271479809)
|
||||
serializeInt32(filterId, buffer: buffer, boxed: false)
|
||||
maxPosition.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "feed.readFeed", parameters: [("filterId", String(describing: filterId)), ("maxPosition", String(describing: maxPosition))]), 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 extension Api.functions.folders {
|
||||
static func deleteFolder(folderId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
|
@ -541,6 +541,7 @@ public extension Api {
|
||||
public extension Api {
|
||||
enum ExportedChatInvite: TypeConstructorDescription {
|
||||
case chatInviteExported(flags: Int32, link: String, adminId: Int64, date: Int32, startDate: Int32?, expireDate: Int32?, usageLimit: Int32?, usage: Int32?, requested: Int32?, title: String?)
|
||||
case chatInvitePublicJoinRequests
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
@ -558,6 +559,12 @@ public extension Api {
|
||||
if Int(flags) & Int(1 << 3) != 0 {serializeInt32(usage!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 7) != 0 {serializeInt32(requested!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 8) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
case .chatInvitePublicJoinRequests:
|
||||
if boxed {
|
||||
buffer.appendInt32(-317687113)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -566,6 +573,8 @@ public extension Api {
|
||||
switch self {
|
||||
case .chatInviteExported(let flags, let link, let adminId, let date, let startDate, let expireDate, let usageLimit, let usage, let requested, let title):
|
||||
return ("chatInviteExported", [("flags", String(describing: flags)), ("link", String(describing: link)), ("adminId", String(describing: adminId)), ("date", String(describing: date)), ("startDate", String(describing: startDate)), ("expireDate", String(describing: expireDate)), ("usageLimit", String(describing: usageLimit)), ("usage", String(describing: usage)), ("requested", String(describing: requested)), ("title", String(describing: title))])
|
||||
case .chatInvitePublicJoinRequests:
|
||||
return ("chatInvitePublicJoinRequests", [])
|
||||
}
|
||||
}
|
||||
|
||||
@ -607,6 +616,9 @@ public extension Api {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_chatInvitePublicJoinRequests(_ reader: BufferReader) -> ExportedChatInvite? {
|
||||
return Api.ExportedChatInvite.chatInvitePublicJoinRequests
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -650,52 +662,6 @@ public extension Api {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api {
|
||||
enum FeedPosition: TypeConstructorDescription {
|
||||
case feedPosition(date: Int32, peer: Api.Peer, id: Int32)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .feedPosition(let date, let peer, let id):
|
||||
if boxed {
|
||||
buffer.appendInt32(1348066419)
|
||||
}
|
||||
serializeInt32(date, buffer: buffer, boxed: false)
|
||||
peer.serialize(buffer, true)
|
||||
serializeInt32(id, buffer: buffer, boxed: false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .feedPosition(let date, let peer, let id):
|
||||
return ("feedPosition", [("date", String(describing: date)), ("peer", String(describing: peer)), ("id", String(describing: id))])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_feedPosition(_ reader: BufferReader) -> FeedPosition? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Api.Peer?
|
||||
if let signature = reader.readInt32() {
|
||||
_2 = Api.parse(reader, signature: signature) as? Api.Peer
|
||||
}
|
||||
var _3: Int32?
|
||||
_3 = reader.readInt32()
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
if _c1 && _c2 && _c3 {
|
||||
return Api.FeedPosition.feedPosition(date: _1!, peer: _2!, id: _3!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api {
|
||||
enum FileHash: TypeConstructorDescription {
|
||||
case fileHash(offset: Int32, limit: Int32, hash: Buffer)
|
||||
|
@ -118,6 +118,12 @@ func parseTelegramGroupOrChannel(chat: Api.Chat) -> Peer? {
|
||||
if (flags & Int32(1 << 27)) != 0 {
|
||||
channelFlags.insert(.copyProtectionEnabled)
|
||||
}
|
||||
if (flags & Int32(1 << 28)) != 0 {
|
||||
channelFlags.insert(.joinToSend)
|
||||
}
|
||||
if (flags & Int32(1 << 29)) != 0 {
|
||||
channelFlags.insert(.requestToJoin)
|
||||
}
|
||||
|
||||
let restrictionInfo: PeerAccessRestrictionInfo?
|
||||
if let restrictionReason = restrictionReason {
|
||||
|
@ -16,13 +16,21 @@ extension BotMenuButton {
|
||||
extension BotInfo {
|
||||
convenience init(apiBotInfo: Api.BotInfo) {
|
||||
switch apiBotInfo {
|
||||
case let .botInfo(_, description, commands, menuButton):
|
||||
self.init(description: description, commands: commands.map { command in
|
||||
switch command {
|
||||
case let .botCommand(command, description):
|
||||
return BotCommand(text: command, description: description)
|
||||
case let .botInfo(_, _, description, _, apiCommands, apiMenuButton):
|
||||
var commands: [BotCommand] = []
|
||||
if let apiCommands = apiCommands {
|
||||
commands = apiCommands.map { command in
|
||||
switch command {
|
||||
case let .botCommand(command, description):
|
||||
return BotCommand(text: command, description: description)
|
||||
}
|
||||
}
|
||||
}, menuButton: BotMenuButton(apiBotMenuButton: menuButton))
|
||||
}
|
||||
var menuButton: BotMenuButton = .commands
|
||||
if let apiMenuButton = apiMenuButton {
|
||||
menuButton = BotMenuButton(apiBotMenuButton: apiMenuButton)
|
||||
}
|
||||
self.init(description: description ?? "", commands: commands, menuButton: menuButton)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,48 @@ import TelegramApi
|
||||
extension ExportedInvitation {
|
||||
init(apiExportedInvite: Api.ExportedChatInvite) {
|
||||
switch apiExportedInvite {
|
||||
case let .chatInviteExported(flags, link, adminId, date, startDate, expireDate, usageLimit, usage, requested, title):
|
||||
self = ExportedInvitation(link: link, title: title, isPermanent: (flags & (1 << 5)) != 0, requestApproval: (flags & (1 << 6)) != 0, isRevoked: (flags & (1 << 0)) != 0, adminId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(adminId)), date: date, startDate: startDate, expireDate: expireDate, usageLimit: usageLimit, count: usage, requestedCount: requested)
|
||||
case let .chatInviteExported(flags, link, adminId, date, startDate, expireDate, usageLimit, usage, requested, title):
|
||||
self = .link(link: link, title: title, isPermanent: (flags & (1 << 5)) != 0, requestApproval: (flags & (1 << 6)) != 0, isRevoked: (flags & (1 << 0)) != 0, adminId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(adminId)), date: date, startDate: startDate, expireDate: expireDate, usageLimit: usageLimit, count: usage, requestedCount: requested)
|
||||
case .chatInvitePublicJoinRequests:
|
||||
self = .publicJoinRequest
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension ExportedInvitation {
|
||||
var link: String? {
|
||||
switch self {
|
||||
case let .link(link, _, _, _, _, _, _, _, _, _, _, _):
|
||||
return link
|
||||
case .publicJoinRequest:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var date: Int32? {
|
||||
switch self {
|
||||
case let .link(_, _, _, _, _, _, _, date, _, _, _, _):
|
||||
return date
|
||||
case .publicJoinRequest:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var isPermanent: Bool {
|
||||
switch self {
|
||||
case let .link(_, _, isPermanent, _, _, _, _, _, _, _, _, _):
|
||||
return isPermanent
|
||||
case .publicJoinRequest:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
var isRevoked: Bool {
|
||||
switch self {
|
||||
case let .link(_, _, _, _, isRevoked, _, _, _, _, _, _, _):
|
||||
return isRevoked
|
||||
case .publicJoinRequest:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,73 +1,81 @@
|
||||
import Postbox
|
||||
|
||||
public struct ExportedInvitation: Codable, Equatable {
|
||||
public let link: String
|
||||
public let title: String?
|
||||
public let isPermanent: Bool
|
||||
public let requestApproval: Bool
|
||||
public let isRevoked: Bool
|
||||
public let adminId: PeerId
|
||||
public let date: Int32
|
||||
public let startDate: Int32?
|
||||
public let expireDate: Int32?
|
||||
public let usageLimit: Int32?
|
||||
public let count: Int32?
|
||||
public let requestedCount: Int32?
|
||||
|
||||
public init(link: String, title: String?, isPermanent: Bool, requestApproval: Bool, isRevoked: Bool, adminId: PeerId, date: Int32, startDate: Int32?, expireDate: Int32?, usageLimit: Int32?, count: Int32?, requestedCount: Int32?) {
|
||||
self.link = link
|
||||
self.title = title
|
||||
self.isPermanent = isPermanent
|
||||
self.requestApproval = requestApproval
|
||||
self.isRevoked = isRevoked
|
||||
self.adminId = adminId
|
||||
self.date = date
|
||||
self.startDate = startDate
|
||||
self.expireDate = expireDate
|
||||
self.usageLimit = usageLimit
|
||||
self.count = count
|
||||
self.requestedCount = requestedCount
|
||||
}
|
||||
public enum ExportedInvitation: Codable, Equatable {
|
||||
case link(link: String, title: String?, isPermanent: Bool, requestApproval: Bool, isRevoked: Bool, adminId: PeerId, date: Int32, startDate: Int32?, expireDate: Int32?, usageLimit: Int32?, count: Int32?, requestedCount: Int32?)
|
||||
case publicJoinRequest
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
self.link = try container.decode(String.self, forKey: "l")
|
||||
self.title = try container.decodeIfPresent(String.self, forKey: "title")
|
||||
self.isPermanent = try container.decode(Bool.self, forKey: "permanent")
|
||||
self.requestApproval = try container.decodeIfPresent(Bool.self, forKey: "requestApproval") ?? false
|
||||
self.isRevoked = try container.decode(Bool.self, forKey: "revoked")
|
||||
self.adminId = PeerId(try container.decode(Int64.self, forKey: "adminId"))
|
||||
self.date = try container.decode(Int32.self, forKey: "date")
|
||||
self.startDate = try container.decodeIfPresent(Int32.self, forKey: "startDate")
|
||||
self.expireDate = try container.decodeIfPresent(Int32.self, forKey: "expireDate")
|
||||
self.usageLimit = try container.decodeIfPresent(Int32.self, forKey: "usageLimit")
|
||||
self.count = try container.decodeIfPresent(Int32.self, forKey: "count")
|
||||
self.requestedCount = try? container.decodeIfPresent(Int32.self, forKey: "requestedCount")
|
||||
let type = try container.decodeIfPresent(Int32.self, forKey: "t") ?? 0
|
||||
if type == 0 {
|
||||
let link = try container.decode(String.self, forKey: "l")
|
||||
let title = try container.decodeIfPresent(String.self, forKey: "title")
|
||||
let isPermanent = try container.decode(Bool.self, forKey: "permanent")
|
||||
let requestApproval = try container.decodeIfPresent(Bool.self, forKey: "requestApproval") ?? false
|
||||
let isRevoked = try container.decode(Bool.self, forKey: "revoked")
|
||||
let adminId = PeerId(try container.decode(Int64.self, forKey: "adminId"))
|
||||
let date = try container.decode(Int32.self, forKey: "date")
|
||||
let startDate = try container.decodeIfPresent(Int32.self, forKey: "startDate")
|
||||
let expireDate = try container.decodeIfPresent(Int32.self, forKey: "expireDate")
|
||||
let usageLimit = try container.decodeIfPresent(Int32.self, forKey: "usageLimit")
|
||||
let count = try container.decodeIfPresent(Int32.self, forKey: "count")
|
||||
let requestedCount = try? container.decodeIfPresent(Int32.self, forKey: "requestedCount")
|
||||
|
||||
self = .link(link: link, title: title, isPermanent: isPermanent, requestApproval: requestApproval, isRevoked: isRevoked, adminId: adminId, date: date, startDate: startDate, expireDate: expireDate, usageLimit: usageLimit, count: count, requestedCount: requestedCount)
|
||||
} else {
|
||||
self = .publicJoinRequest
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
try container.encode(self.link, forKey: "l")
|
||||
try container.encodeIfPresent(self.title, forKey: "title")
|
||||
try container.encode(self.isPermanent, forKey: "permanent")
|
||||
try container.encode(self.requestApproval, forKey: "requestApproval")
|
||||
try container.encode(self.isRevoked, forKey: "revoked")
|
||||
try container.encode(self.adminId.toInt64(), forKey: "adminId")
|
||||
try container.encode(self.date, forKey: "date")
|
||||
try container.encodeIfPresent(self.startDate, forKey: "startDate")
|
||||
try container.encodeIfPresent(self.expireDate, forKey: "expireDate")
|
||||
try container.encodeIfPresent(self.usageLimit, forKey: "usageLimit")
|
||||
try container.encodeIfPresent(self.count, forKey: "count")
|
||||
try container.encodeIfPresent(self.requestedCount, forKey: "requestedCount")
|
||||
switch self {
|
||||
case let .link(link, title, isPermanent, requestApproval, isRevoked, adminId, date, startDate, expireDate, usageLimit, count, requestedCount):
|
||||
let type: Int32 = 0
|
||||
try container.encode(type, forKey: "t")
|
||||
try container.encode(link, forKey: "l")
|
||||
try container.encodeIfPresent(title, forKey: "title")
|
||||
try container.encode(isPermanent, forKey: "permanent")
|
||||
try container.encode(requestApproval, forKey: "requestApproval")
|
||||
try container.encode(isRevoked, forKey: "revoked")
|
||||
try container.encode(adminId.toInt64(), forKey: "adminId")
|
||||
try container.encode(date, forKey: "date")
|
||||
try container.encodeIfPresent(startDate, forKey: "startDate")
|
||||
try container.encodeIfPresent(expireDate, forKey: "expireDate")
|
||||
try container.encodeIfPresent(usageLimit, forKey: "usageLimit")
|
||||
try container.encodeIfPresent(count, forKey: "count")
|
||||
try container.encodeIfPresent(requestedCount, forKey: "requestedCount")
|
||||
case .publicJoinRequest:
|
||||
let type: Int32 = 1
|
||||
try container.encode(type, forKey: "t")
|
||||
}
|
||||
}
|
||||
|
||||
public static func ==(lhs: ExportedInvitation, rhs: ExportedInvitation) -> Bool {
|
||||
return lhs.link == rhs.link && lhs.title == rhs.title && lhs.isPermanent == rhs.isPermanent && lhs.requestApproval == rhs.requestApproval && lhs.isRevoked == rhs.isRevoked && lhs.adminId == rhs.adminId && lhs.date == rhs.date && lhs.startDate == rhs.startDate && lhs.expireDate == rhs.expireDate && lhs.usageLimit == rhs.usageLimit && lhs.count == rhs.count && lhs.requestedCount == rhs.requestedCount
|
||||
switch lhs {
|
||||
case let .link(link, title, isPermanent, requestApproval, isRevoked, adminId, date, startDate, expireDate, usageLimit, count, requestedCount):
|
||||
if case .link(link, title, isPermanent, requestApproval, isRevoked, adminId, date, startDate, expireDate, usageLimit, count, requestedCount) = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case .publicJoinRequest:
|
||||
if case .publicJoinRequest = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func withUpdated(isRevoked: Bool) -> ExportedInvitation {
|
||||
return ExportedInvitation(link: self.link, title: self.title, isPermanent: self.isPermanent, requestApproval: self.requestApproval, isRevoked: isRevoked, adminId: self.adminId, date: self.date, startDate: self.startDate, expireDate: self.expireDate, usageLimit: self.usageLimit, count: self.count, requestedCount: self.requestedCount)
|
||||
switch self {
|
||||
case let .link(link, title, isPermanent, requestApproval, _, adminId, date, startDate, expireDate, usageLimit, count, requestedCount):
|
||||
return .link(link: link, title: title, isPermanent: isPermanent, requestApproval: requestApproval, isRevoked: isRevoked, adminId: adminId, date: date, startDate: startDate, expireDate: expireDate, usageLimit: usageLimit, count: count, requestedCount: requestedCount)
|
||||
case .publicJoinRequest:
|
||||
return .publicJoinRequest
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -145,6 +145,8 @@ public struct TelegramChannelFlags: OptionSet {
|
||||
public static let isFake = TelegramChannelFlags(rawValue: 1 << 6)
|
||||
public static let isGigagroup = TelegramChannelFlags(rawValue: 1 << 7)
|
||||
public static let copyProtectionEnabled = TelegramChannelFlags(rawValue: 1 << 8)
|
||||
public static let joinToSend = TelegramChannelFlags(rawValue: 1 << 9)
|
||||
public static let requestToJoin = TelegramChannelFlags(rawValue: 1 << 10)
|
||||
}
|
||||
|
||||
public final class TelegramChannel: Peer, Equatable {
|
||||
|
@ -343,112 +343,112 @@ private class FeedHistoryContextImpl {
|
||||
|
||||
private func fetchHole(entry: MessageHistoryHolesViewEntry) -> Signal<State, NoError> {
|
||||
//feed.getFeed flags:# filter_id:int offset_to_max_read:flags.3?true offset_position:flags.0?FeedPosition add_offset:int limit:int max_position:flags.1?FeedPosition min_position:flags.2?FeedPosition hash:long = messages.FeedMessages;
|
||||
|
||||
let offsetPosition: Api.FeedPosition?
|
||||
let addOffset: Int32 = 0
|
||||
|
||||
switch entry.direction {
|
||||
case let .range(start, end):
|
||||
if min(start.id, end.id) == 1 && max(start.id, end.id) == Int32.max - 1 {
|
||||
offsetPosition = nil
|
||||
} else {
|
||||
return .never()
|
||||
}
|
||||
case let .aroundId(id):
|
||||
let _ = id
|
||||
return .never()
|
||||
}
|
||||
|
||||
var flags: Int32 = 0
|
||||
if let _ = offsetPosition {
|
||||
flags |= 1 << 0
|
||||
}
|
||||
|
||||
let account = self.account
|
||||
let state = self.stateValue
|
||||
return self.account.network.request(Api.functions.feed.getFeed(
|
||||
flags: flags,
|
||||
filterId: self.feedId,
|
||||
offsetPosition: offsetPosition,
|
||||
addOffset: addOffset,
|
||||
limit: 100,
|
||||
maxPosition: nil,
|
||||
minPosition: nil,
|
||||
hash: 0
|
||||
))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.feed.FeedMessages?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<State, NoError> in
|
||||
return account.postbox.transaction { transaction -> State in
|
||||
guard let result = result else {
|
||||
var updatedState = state ?? State(messageIndices: [], holeIndices: [:])
|
||||
updatedState.holeIndices = [:]
|
||||
return updatedState
|
||||
}
|
||||
|
||||
let messages: [Api.Message]
|
||||
let chats: [Api.Chat]
|
||||
let users: [Api.User]
|
||||
|
||||
switch result {
|
||||
case let .feedMessages(_, _, _, _, apiMessages, apiChats, apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case .feedMessagesNotModified:
|
||||
messages = []
|
||||
users = []
|
||||
chats = []
|
||||
}
|
||||
|
||||
var peers: [Peer] = []
|
||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
||||
for chat in chats {
|
||||
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||
peers.append(groupOrChannel)
|
||||
}
|
||||
}
|
||||
for user in users {
|
||||
let telegramUser = TelegramUser(user: user)
|
||||
peers.append(telegramUser)
|
||||
if let presence = TelegramUserPresence(apiUser: user) {
|
||||
peerPresences[telegramUser.id] = presence
|
||||
}
|
||||
}
|
||||
|
||||
var storeMessages: [StoreMessage] = []
|
||||
|
||||
for message in messages {
|
||||
if let storeMessage = StoreMessage(apiMessage: message, namespace: Namespaces.Message.Cloud) {
|
||||
storeMessages.append(storeMessage)
|
||||
}
|
||||
}
|
||||
|
||||
updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in
|
||||
return updated
|
||||
})
|
||||
updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences)
|
||||
|
||||
let _ = transaction.addMessages(storeMessages, location: .Random)
|
||||
|
||||
var updatedState = state ?? State(messageIndices: [], holeIndices: [:])
|
||||
var currentSet = Set<MessageIndex>(updatedState.messageIndices)
|
||||
|
||||
for index in storeMessages.compactMap(\.index) {
|
||||
if !currentSet.contains(index) {
|
||||
currentSet.insert(index)
|
||||
}
|
||||
updatedState.messageIndices.append(index)
|
||||
}
|
||||
|
||||
updatedState.messageIndices.sort()
|
||||
|
||||
updatedState.holeIndices = [:]
|
||||
return updatedState
|
||||
}
|
||||
}
|
||||
return .complete()
|
||||
// let offsetPosition: Api.FeedPosition?
|
||||
// let addOffset: Int32 = 0
|
||||
//
|
||||
// switch entry.direction {
|
||||
// case let .range(start, end):
|
||||
// if min(start.id, end.id) == 1 && max(start.id, end.id) == Int32.max - 1 {
|
||||
// offsetPosition = nil
|
||||
// } else {
|
||||
// return .never()
|
||||
// }
|
||||
// case let .aroundId(id):
|
||||
// let _ = id
|
||||
// return .never()
|
||||
// }
|
||||
//
|
||||
// var flags: Int32 = 0
|
||||
// if let _ = offsetPosition {
|
||||
// flags |= 1 << 0
|
||||
// }
|
||||
//
|
||||
// let account = self.account
|
||||
// let state = self.stateValue
|
||||
// return self.account.network.request(Api.functions.feed.getFeed(
|
||||
// flags: flags,
|
||||
// filterId: self.feedId,
|
||||
// offsetPosition: offsetPosition,
|
||||
// addOffset: addOffset,
|
||||
// limit: 100,
|
||||
// maxPosition: nil,
|
||||
// minPosition: nil,
|
||||
// hash: 0
|
||||
// ))
|
||||
// |> map(Optional.init)
|
||||
// |> `catch` { _ -> Signal<Api.feed.FeedMessages?, NoError> in
|
||||
// return .single(nil)
|
||||
// }
|
||||
// |> mapToSignal { result -> Signal<State, NoError> in
|
||||
// return account.postbox.transaction { transaction -> State in
|
||||
// guard let result = result else {
|
||||
// var updatedState = state ?? State(messageIndices: [], holeIndices: [:])
|
||||
// updatedState.holeIndices = [:]
|
||||
// return updatedState
|
||||
// }
|
||||
//
|
||||
// let messages: [Api.Message]
|
||||
// let chats: [Api.Chat]
|
||||
// let users: [Api.User]
|
||||
//
|
||||
// switch result {
|
||||
// case let .feedMessages(_, _, _, _, apiMessages, apiChats, apiUsers):
|
||||
// messages = apiMessages
|
||||
// chats = apiChats
|
||||
// users = apiUsers
|
||||
// case .feedMessagesNotModified:
|
||||
// messages = []
|
||||
// users = []
|
||||
// chats = []
|
||||
// }
|
||||
//
|
||||
// var peers: [Peer] = []
|
||||
// var peerPresences: [PeerId: PeerPresence] = [:]
|
||||
// for chat in chats {
|
||||
// if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||
// peers.append(groupOrChannel)
|
||||
// }
|
||||
// }
|
||||
// for user in users {
|
||||
// let telegramUser = TelegramUser(user: user)
|
||||
// peers.append(telegramUser)
|
||||
// if let presence = TelegramUserPresence(apiUser: user) {
|
||||
// peerPresences[telegramUser.id] = presence
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// var storeMessages: [StoreMessage] = []
|
||||
//
|
||||
// for message in messages {
|
||||
// if let storeMessage = StoreMessage(apiMessage: message, namespace: Namespaces.Message.Cloud) {
|
||||
// storeMessages.append(storeMessage)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in
|
||||
// return updated
|
||||
// })
|
||||
// updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences)
|
||||
//
|
||||
// let _ = transaction.addMessages(storeMessages, location: .Random)
|
||||
//
|
||||
// var updatedState = state ?? State(messageIndices: [], holeIndices: [:])
|
||||
// var currentSet = Set<MessageIndex>(updatedState.messageIndices)
|
||||
//
|
||||
// for index in storeMessages.compactMap(\.index) {
|
||||
// if !currentSet.contains(index) {
|
||||
// currentSet.insert(index)
|
||||
// }
|
||||
// updatedState.messageIndices.append(index)
|
||||
// }
|
||||
//
|
||||
// updatedState.messageIndices.sort()
|
||||
//
|
||||
// updatedState.holeIndices = [:]
|
||||
// return updatedState
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
func applyMaxReadIndex(messageIndex: MessageIndex) {
|
||||
|
@ -0,0 +1,51 @@
|
||||
import Postbox
|
||||
import TelegramApi
|
||||
import SwiftSignalKit
|
||||
|
||||
public enum UpdateChannelJoinToSendError {
|
||||
case generic
|
||||
}
|
||||
|
||||
func _internal_toggleChannelJoinToSend(postbox: Postbox, network: Network, accountStateManager: AccountStateManager, peerId: PeerId, enabled: Bool) -> Signal<Never, UpdateChannelJoinToSendError> {
|
||||
return postbox.transaction { transaction -> Peer? in
|
||||
return transaction.getPeer(peerId)
|
||||
}
|
||||
|> castError(UpdateChannelJoinToSendError.self)
|
||||
|> mapToSignal { peer in
|
||||
guard let peer = peer, let inputChannel = apiInputChannel(peer) else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
return network.request(Api.functions.channels.toggleJoinToSend(channel: inputChannel, enabled: enabled ? .boolTrue : .boolFalse))
|
||||
|> `catch` { _ -> Signal<Api.Updates, UpdateChannelJoinToSendError> in
|
||||
return .fail(.generic)
|
||||
}
|
||||
|> mapToSignal { updates -> Signal<Never, UpdateChannelJoinToSendError> in
|
||||
accountStateManager.addUpdates(updates)
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum UpdateChannelJoinRequestError {
|
||||
case generic
|
||||
}
|
||||
|
||||
func _internal_toggleChannelJoinRequest(postbox: Postbox, network: Network, accountStateManager: AccountStateManager, peerId: PeerId, enabled: Bool) -> Signal<Never, UpdateChannelJoinRequestError> {
|
||||
return postbox.transaction { transaction -> Peer? in
|
||||
return transaction.getPeer(peerId)
|
||||
}
|
||||
|> castError(UpdateChannelJoinRequestError.self)
|
||||
|> mapToSignal { peer in
|
||||
guard let peer = peer, let inputChannel = apiInputChannel(peer) else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
return network.request(Api.functions.channels.toggleJoinRequest(channel: inputChannel, enabled: enabled ? .boolTrue : .boolFalse))
|
||||
|> `catch` { _ -> Signal<Api.Updates, UpdateChannelJoinRequestError> in
|
||||
return .fail(.generic)
|
||||
}
|
||||
|> mapToSignal { updates -> Signal<Never, UpdateChannelJoinRequestError> in
|
||||
accountStateManager.addUpdates(updates)
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
}
|
@ -245,7 +245,7 @@ func _internal_peerExportedInvitations(account: Account, peerId: PeerId, revoked
|
||||
return account.postbox.transaction { transaction -> Signal<ExportedInvitations?, NoError> in
|
||||
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer), let adminPeer = transaction.getPeer(adminId ?? account.peerId), let adminId = apiInputUser(adminPeer) {
|
||||
var flags: Int32 = 0
|
||||
if let _ = offsetLink {
|
||||
if let _ = offsetLink?.date {
|
||||
flags |= (1 << 2)
|
||||
}
|
||||
if revoked {
|
||||
@ -828,19 +828,27 @@ private final class PeerInvitationImportersContextImpl {
|
||||
case let .requests(maybeQuery):
|
||||
query = maybeQuery
|
||||
}
|
||||
self.link = invite?.link
|
||||
|
||||
var link: String?
|
||||
var count: Int32 = 0
|
||||
if let invite = invite, case let .link(inviteLink, _, _, _, _, _, _, _, _, _, inviteCount, _) = invite {
|
||||
link = inviteLink
|
||||
if let inviteCount = inviteCount {
|
||||
count = inviteCount
|
||||
}
|
||||
}
|
||||
self.link = link
|
||||
self.count = count
|
||||
|
||||
self.requested = requested
|
||||
self.query = query
|
||||
|
||||
let count = invite?.count ?? 0
|
||||
self.count = count
|
||||
|
||||
self.isLoadingMore = true
|
||||
self.disposable.set((account.postbox.transaction { transaction -> (peers: [PeerInvitationImportersState.Importer], count: Int32, canLoadMore: Bool)? in
|
||||
guard query == nil else {
|
||||
return nil
|
||||
}
|
||||
let cachedResult = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerInvitationImporters, key: CachedPeerInvitationImporters.key(peerId: peerId, link: invite?.link ?? "requests", requested: self.requested)))?.get(CachedPeerInvitationImporters.self)
|
||||
let cachedResult = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerInvitationImporters, key: CachedPeerInvitationImporters.key(peerId: peerId, link: link ?? "requests", requested: requested)))?.get(CachedPeerInvitationImporters.self)
|
||||
if let cachedResult = cachedResult, (Int(cachedResult.count) == count || invite == nil) {
|
||||
var result: [PeerInvitationImportersState.Importer] = []
|
||||
for peerId in cachedResult.peerIds {
|
||||
|
@ -9,6 +9,7 @@ public enum JoinChannelError {
|
||||
case generic
|
||||
case tooMuchJoined
|
||||
case tooMuchUsers
|
||||
case inviteRequestSent
|
||||
}
|
||||
|
||||
func _internal_joinChannel(account: Account, peerId: PeerId, hash: String?) -> Signal<RenderedChannelParticipant?, JoinChannelError> {
|
||||
@ -30,6 +31,8 @@ func _internal_joinChannel(account: Account, peerId: PeerId, hash: String?) -> S
|
||||
return .tooMuchJoined
|
||||
case "USERS_TOO_MUCH":
|
||||
return .tooMuchUsers
|
||||
case "INVITE_REQUEST_SENT":
|
||||
return .inviteRequestSent
|
||||
default:
|
||||
return .generic
|
||||
}
|
||||
|
@ -246,6 +246,14 @@ public extension TelegramEngine {
|
||||
public func toggleMessageCopyProtection(peerId: PeerId, enabled: Bool) -> Signal<Void, NoError> {
|
||||
return _internal_toggleMessageCopyProtection(account: self.account, peerId: peerId, enabled: enabled)
|
||||
}
|
||||
|
||||
public func toggleChannelJoinToSend(peerId: PeerId, enabled: Bool) -> Signal<Never, UpdateChannelJoinToSendError> {
|
||||
return _internal_toggleChannelJoinToSend(postbox: self.account.postbox, network: self.account.network, accountStateManager: self.account.stateManager, peerId: peerId, enabled: enabled)
|
||||
}
|
||||
|
||||
public func toggleChannelJoinRequest(peerId: PeerId, enabled: Bool) -> Signal<Never, UpdateChannelJoinRequestError> {
|
||||
return _internal_toggleChannelJoinRequest(postbox: self.account.postbox, network: self.account.network, accountStateManager: self.account.stateManager, peerId: peerId, enabled: enabled)
|
||||
}
|
||||
|
||||
public func requestPeerPhotos(peerId: PeerId) -> Signal<[TelegramPeerPhoto], NoError> {
|
||||
return _internal_requestPeerPhotos(postbox: self.account.postbox, network: self.account.network, peerId: peerId)
|
||||
|
@ -5,7 +5,7 @@ import TelegramApi
|
||||
import MtProtoKit
|
||||
|
||||
|
||||
func _internal_toggleShouldChannelMessagesSignatures(account:Account, peerId:PeerId, enabled: Bool) -> Signal<Void, NoError> {
|
||||
func _internal_toggleShouldChannelMessagesSignatures(account: Account, peerId: PeerId, enabled: Bool) -> Signal<Void, NoError> {
|
||||
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
if let peer = transaction.getPeer(peerId) as? TelegramChannel, let inputChannel = apiInputChannel(peer) {
|
||||
return account.network.request(Api.functions.channels.toggleSignatures(channel: inputChannel, enabled: enabled ? .boolTrue : .boolFalse)) |> retryRequest |> map { updates -> Void in
|
||||
|
@ -278,10 +278,12 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
||||
var botInfos: [CachedPeerBotInfo] = []
|
||||
for botInfo in chatFullBotInfo ?? [] {
|
||||
switch botInfo {
|
||||
case let .botInfo(userId, _, _, _):
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
|
||||
let parsedBotInfo = BotInfo(apiBotInfo: botInfo)
|
||||
botInfos.append(CachedPeerBotInfo(peerId: peerId, botInfo: parsedBotInfo))
|
||||
case let .botInfo(_, userId, _, _, _, _):
|
||||
if let userId = userId {
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
|
||||
let parsedBotInfo = BotInfo(apiBotInfo: botInfo)
|
||||
botInfos.append(CachedPeerBotInfo(peerId: peerId, botInfo: parsedBotInfo))
|
||||
}
|
||||
}
|
||||
}
|
||||
let participants = CachedGroupParticipants(apiParticipants: chatFullParticipants)
|
||||
@ -449,10 +451,12 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
||||
var botInfos: [CachedPeerBotInfo] = []
|
||||
for botInfo in apiBotInfos {
|
||||
switch botInfo {
|
||||
case let .botInfo(userId, _, _, _):
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
|
||||
let parsedBotInfo = BotInfo(apiBotInfo: botInfo)
|
||||
botInfos.append(CachedPeerBotInfo(peerId: peerId, botInfo: parsedBotInfo))
|
||||
case let .botInfo(_, userId, _, _, _, _):
|
||||
if let userId = userId {
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
|
||||
let parsedBotInfo = BotInfo(apiBotInfo: botInfo)
|
||||
botInfos.append(CachedPeerBotInfo(peerId: peerId, botInfo: parsedBotInfo))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
{"v":"5.1.2","fr":60,"ip":0,"op":3600,"w":228,"h":228,"nm":"mute","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"un Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[117.875,88.875,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.863,0.863,-0.19]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p833_0p863_0p333_0","0p833_0p863_0p333_0","0p833_-0p19_0p333_0"],"t":0,"s":[0,0,100],"e":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.365,0.365,0.476]},"n":["0p667_1_0p167_0p365","0p667_1_0p167_0p365","0p667_1_0p167_0p476"],"t":10,"s":[100,100,100],"e":[115,115,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":14,"s":[115,115,100],"e":[100,100,100]},{"t":25}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-34,-34],[-33.992,-34]],"c":false}],"e":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-34,-34],[34,34]],"c":false}]},{"t":15}],"ix":2,"x":"var $bm_rt;\n$bm_rt = content('Group 1').content('Path 1').path;"},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":10,"nm":"Stroke 2","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.584313750267,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[256,256],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"mute Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[111,88.781,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.863,0.863,-12.69]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p833_0p863_0p333_0","0p833_0p863_0p333_0","0p833_-12p69_0p333_0"],"t":0,"s":[0,0,100],"e":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.365,0.365,5.476]},"n":["0p667_1_0p167_0p365","0p667_1_0p167_0p365","0p667_1_0p167_5p476"],"t":10,"s":[100,100,100],"e":[115,115,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":14,"s":[115,115,100],"e":[100,100,100]},{"t":25}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.995,-0.904],[0,0],[0.746,0],[0,0],[0,-3.866],[0,0],[-3.866,0],[0,0],[-0.552,-0.503],[0,0],[-2.006,2.207],[0,1.343],[0,0],[2.982,0]],"o":[[0,0],[-0.552,0.502],[0,0],[-3.866,0],[0,0],[0,3.866],[0,0],[0.746,0],[0,0],[2.207,2.007],[0.903,-0.995],[0,0],[0,-2.982],[-1.343,0]],"v":[[16.967,-36.589],[-6.142,-15.581],[-8.16,-14.801],[-19,-14.801],[-26,-7.801],[-26,7.199],[-19,14.199],[-8.16,14.199],[-6.142,14.98],[16.967,35.987],[24.596,35.625],[26,31.992],[26,-32.594],[20.6,-37.994]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[256,256.994],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0}],"markers":[]}
|
||||
{"v":"5.1.2","fr":60,"ip":0,"op":180,"w":228,"h":228,"nm":"mute","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"un Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[117.875,88.875,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.863,0.863,-0.19]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p833_0p863_0p333_0","0p833_0p863_0p333_0","0p833_-0p19_0p333_0"],"t":0,"s":[0,0,100],"e":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.365,0.365,0.476]},"n":["0p667_1_0p167_0p365","0p667_1_0p167_0p365","0p667_1_0p167_0p476"],"t":10,"s":[100,100,100],"e":[115,115,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":14,"s":[115,115,100],"e":[100,100,100]},{"t":25}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-34,-34],[-33.992,-34]],"c":false}],"e":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-34,-34],[34,34]],"c":false}]},{"t":15}],"ix":2,"x":"var $bm_rt;\n$bm_rt = content('Group 1').content('Path 1').path;"},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":10,"nm":"Stroke 2","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.584313750267,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[256,256],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"mute Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[111,88.781,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.863,0.863,-12.69]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p833_0p863_0p333_0","0p833_0p863_0p333_0","0p833_-12p69_0p333_0"],"t":0,"s":[0,0,100],"e":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.365,0.365,5.476]},"n":["0p667_1_0p167_0p365","0p667_1_0p167_0p365","0p667_1_0p167_5p476"],"t":10,"s":[100,100,100],"e":[115,115,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":14,"s":[115,115,100],"e":[100,100,100]},{"t":25}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.995,-0.904],[0,0],[0.746,0],[0,0],[0,-3.866],[0,0],[-3.866,0],[0,0],[-0.552,-0.503],[0,0],[-2.006,2.207],[0,1.343],[0,0],[2.982,0]],"o":[[0,0],[-0.552,0.502],[0,0],[-3.866,0],[0,0],[0,3.866],[0,0],[0.746,0],[0,0],[2.207,2.007],[0.903,-0.995],[0,0],[0,-2.982],[-1.343,0]],"v":[[16.967,-36.589],[-6.142,-15.581],[-8.16,-14.801],[-19,-14.801],[-26,-7.801],[-26,7.199],[-19,14.199],[-8.16,14.199],[-6.142,14.98],[16.967,35.987],[24.596,35.625],[26,31.992],[26,-32.594],[20.6,-37.994]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[256,256.994],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"bm":0}],"markers":[]}
|
||||
|
@ -1 +1 @@
|
||||
{"v":"5.1.2","fr":60,"ip":0,"op":3600,"w":228,"h":228,"nm":"pinchat","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"pin Outlines","sr":1,"ks":{"o":{"a":0,"k":99,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[113.656,86.516,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.872,0.872,-10.015]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p833_0p872_0p333_0","0p833_0p872_0p333_0","0p833_-10p015_0p333_0"],"t":0,"s":[0,0,100],"e":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.426,0.426,5.508]},"n":["0p667_1_0p167_0p426","0p667_1_0p167_0p426","0p667_1_0p167_5p508"],"t":10,"s":[100,100,100],"e":[115,115,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":15,"s":[115,115,100],"e":[100,100,100]},{"t":24}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.682,-2.385],[0,0],[7.227,-5.009],[0.494,-0.402],[0.078,-0.079],[-1.265,-1.266],[0,0],[-0.087,-0.07],[-1.129,1.388],[-0.211,0.297],[2.361,8.281],[0,0],[3.76,3.76],[0,0],[2.035,0]],"o":[[0,0],[-8.176,-2.331],[-0.37,0.258],[-0.086,0.07],[-1.265,1.265],[0,0],[0.079,0.078],[1.388,1.129],[0.312,-0.384],[5.172,-7.273],[0,0],[4.348,-3.067],[0,0],[-1.701,-1.701],[-2.465,0]],"v":[[10.943,-36.491],[-1.24,-19.219],[-25.643,-15.202],[-26.94,-14.213],[-27.187,-13.99],[-27.187,-9.408],[8.801,26.579],[9.049,26.802],[13.607,26.332],[14.391,25.311],[18.607,0.628],[35.879,-11.556],[36.955,-23.925],[23.313,-37.567],[17.514,-40.1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-40.714,40.1],[-7.985,15.793],[-16.406,7.372]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[256.714,257.1],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0}],"markers":[]}
|
||||
{"v":"5.1.2","fr":60,"ip":0,"op":180,"w":228,"h":228,"nm":"pinchat","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"pin Outlines","sr":1,"ks":{"o":{"a":0,"k":99,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[113.656,86.516,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.872,0.872,-10.015]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p833_0p872_0p333_0","0p833_0p872_0p333_0","0p833_-10p015_0p333_0"],"t":0,"s":[0,0,100],"e":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.426,0.426,5.508]},"n":["0p667_1_0p167_0p426","0p667_1_0p167_0p426","0p667_1_0p167_5p508"],"t":10,"s":[100,100,100],"e":[115,115,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":15,"s":[115,115,100],"e":[100,100,100]},{"t":24}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.682,-2.385],[0,0],[7.227,-5.009],[0.494,-0.402],[0.078,-0.079],[-1.265,-1.266],[0,0],[-0.087,-0.07],[-1.129,1.388],[-0.211,0.297],[2.361,8.281],[0,0],[3.76,3.76],[0,0],[2.035,0]],"o":[[0,0],[-8.176,-2.331],[-0.37,0.258],[-0.086,0.07],[-1.265,1.265],[0,0],[0.079,0.078],[1.388,1.129],[0.312,-0.384],[5.172,-7.273],[0,0],[4.348,-3.067],[0,0],[-1.701,-1.701],[-2.465,0]],"v":[[10.943,-36.491],[-1.24,-19.219],[-25.643,-15.202],[-26.94,-14.213],[-27.187,-13.99],[-27.187,-9.408],[8.801,26.579],[9.049,26.802],[13.607,26.332],[14.391,25.311],[18.607,0.628],[35.879,-11.556],[36.955,-23.925],[23.313,-37.567],[17.514,-40.1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-40.714,40.1],[-7.985,15.793],[-16.406,7.372]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[256.714,257.1],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"bm":0}],"markers":[]}
|
||||
|
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
{"v":"5.1.2","fr":60,"ip":0,"op":3600,"w":228,"h":228,"nm":"unpinpinchat","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"un Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[118,84.062,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.872,0.872,-11.778]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p833_0p872_0p333_0","0p833_0p872_0p333_0","0p833_-11p778_0p333_0"],"t":0,"s":[0,0,100],"e":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.426,0.426,6.389]},"n":["0p667_1_0p167_0p426","0p667_1_0p167_0p426","0p667_1_0p167_6p389"],"t":10,"s":[100,100,100],"e":[115,115,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":15,"s":[115,115,100],"e":[100,100,100]},{"t":24}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-34,-34],[-33.992,-34]],"c":false}],"e":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-34,-34],[34,34]],"c":false}]},{"t":15}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":10,"nm":"Stroke 2","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"st","c":{"a":0,"k":[0.097999999102,0.57599995931,0.980000035903,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[256,256],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"pin Outlines","sr":1,"ks":{"o":{"a":0,"k":99,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[113.656,86.516,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.859,0.859,-13.056]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p833_0p859_0p333_0","0p833_0p859_0p333_0","0p833_-13p056_0p333_0"],"t":0,"s":[0,0,100],"e":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.341,0.341,5.111]},"n":["0p667_1_0p167_0p341","0p667_1_0p167_0p341","0p667_1_0p167_5p111"],"t":11,"s":[100,100,100],"e":[115,115,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":15,"s":[115,115,100],"e":[100,100,100]},{"t":24}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.682,-2.385],[0,0],[7.227,-5.009],[0.494,-0.402],[0.078,-0.079],[-1.265,-1.266],[0,0],[-0.087,-0.07],[-1.129,1.388],[-0.211,0.297],[2.361,8.281],[0,0],[3.76,3.76],[0,0],[2.035,0]],"o":[[0,0],[-8.176,-2.331],[-0.37,0.258],[-0.086,0.07],[-1.265,1.265],[0,0],[0.079,0.078],[1.388,1.129],[0.312,-0.384],[5.172,-7.273],[0,0],[4.348,-3.067],[0,0],[-1.701,-1.701],[-2.465,0]],"v":[[10.943,-36.491],[-1.24,-19.219],[-25.643,-15.202],[-26.94,-14.213],[-27.187,-13.99],[-27.187,-9.408],[8.801,26.579],[9.049,26.802],[13.607,26.332],[14.391,25.311],[18.607,0.628],[35.879,-11.556],[36.955,-23.925],[23.313,-37.567],[17.514,-40.1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-40.714,40.1],[-7.985,15.793],[-16.406,7.372]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[256.714,257.1],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0}],"markers":[]}
|
||||
{"v":"5.1.2","fr":60,"ip":0,"op":180,"w":228,"h":228,"nm":"unpinpinchat","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"un Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[118,84.062,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.872,0.872,-11.778]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p833_0p872_0p333_0","0p833_0p872_0p333_0","0p833_-11p778_0p333_0"],"t":0,"s":[0,0,100],"e":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.426,0.426,6.389]},"n":["0p667_1_0p167_0p426","0p667_1_0p167_0p426","0p667_1_0p167_6p389"],"t":10,"s":[100,100,100],"e":[115,115,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":15,"s":[115,115,100],"e":[100,100,100]},{"t":24}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-34,-34],[-33.992,-34]],"c":false}],"e":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-34,-34],[34,34]],"c":false}]},{"t":15}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":10,"nm":"Stroke 2","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"st","c":{"a":0,"k":[0.097999999102,0.57599995931,0.980000035903,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"lc":2,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[256,256],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"pin Outlines","sr":1,"ks":{"o":{"a":0,"k":99,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[113.656,86.516,0],"ix":2},"a":{"a":0,"k":[256,256,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.859,0.859,-13.056]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p833_0p859_0p333_0","0p833_0p859_0p333_0","0p833_-13p056_0p333_0"],"t":0,"s":[0,0,100],"e":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.341,0.341,5.111]},"n":["0p667_1_0p167_0p341","0p667_1_0p167_0p341","0p667_1_0p167_5p111"],"t":11,"s":[100,100,100],"e":[115,115,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":15,"s":[115,115,100],"e":[100,100,100]},{"t":24}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.682,-2.385],[0,0],[7.227,-5.009],[0.494,-0.402],[0.078,-0.079],[-1.265,-1.266],[0,0],[-0.087,-0.07],[-1.129,1.388],[-0.211,0.297],[2.361,8.281],[0,0],[3.76,3.76],[0,0],[2.035,0]],"o":[[0,0],[-8.176,-2.331],[-0.37,0.258],[-0.086,0.07],[-1.265,1.265],[0,0],[0.079,0.078],[1.388,1.129],[0.312,-0.384],[5.172,-7.273],[0,0],[4.348,-3.067],[0,0],[-1.701,-1.701],[-2.465,0]],"v":[[10.943,-36.491],[-1.24,-19.219],[-25.643,-15.202],[-26.94,-14.213],[-27.187,-13.99],[-27.187,-9.408],[8.801,26.579],[9.049,26.802],[13.607,26.332],[14.391,25.311],[18.607,0.628],[35.879,-11.556],[36.955,-23.925],[23.313,-37.567],[17.514,-40.1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-40.714,40.1],[-7.985,15.793],[-16.406,7.372]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[256.714,257.1],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"bm":0}],"markers":[]}
|
||||
|
@ -14,6 +14,8 @@ import ChatPresentationInterfaceState
|
||||
|
||||
private enum SubscriberAction: Equatable {
|
||||
case join
|
||||
case joinGroup
|
||||
case applyToJoin
|
||||
case kicked
|
||||
case muteNotifications
|
||||
case unmuteNotifications
|
||||
@ -25,6 +27,10 @@ private func titleAndColorForAction(_ action: SubscriberAction, theme: Presentat
|
||||
switch action {
|
||||
case .join:
|
||||
return (strings.Channel_JoinChannel, theme.chat.inputPanel.panelControlAccentColor)
|
||||
case .joinGroup:
|
||||
return (strings.Group_JoinGroup, theme.chat.inputPanel.panelControlAccentColor)
|
||||
case .applyToJoin:
|
||||
return (strings.Group_ApplyToJoin, theme.chat.inputPanel.panelControlAccentColor)
|
||||
case .kicked:
|
||||
return (strings.Channel_JoinChannel, theme.chat.inputPanel.panelControlDisabledColor)
|
||||
case .muteNotifications:
|
||||
@ -75,7 +81,15 @@ private func actionForPeer(peer: Peer, interfaceState: ChatPresentationInterface
|
||||
case .kicked:
|
||||
return .kicked
|
||||
case .left:
|
||||
return .join
|
||||
if case .group = channel.info {
|
||||
if channel.flags.contains(.requestToJoin) {
|
||||
return .applyToJoin
|
||||
} else {
|
||||
return .joinGroup
|
||||
}
|
||||
} else {
|
||||
return .join
|
||||
}
|
||||
case .member:
|
||||
if isMuted {
|
||||
return .unmuteNotifications
|
||||
@ -175,7 +189,7 @@ final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode {
|
||||
}
|
||||
|
||||
switch action {
|
||||
case .join:
|
||||
case .join, .joinGroup, .applyToJoin:
|
||||
var delayActivity = false
|
||||
if let peer = peer as? TelegramChannel, case .broadcast = peer.info {
|
||||
delayActivity = true
|
||||
@ -212,6 +226,10 @@ final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode {
|
||||
}
|
||||
let text: String
|
||||
switch error {
|
||||
case .inviteRequestSent:
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
strongSelf.interfaceInteraction?.presentController(UndoOverlayController(presentationData: presentationData, content: .inviteRequestSent(title: presentationInterfaceState.strings.Group_RequestToJoinSent, text: presentationInterfaceState.strings.Group_RequestToJoinSentDescriptionGroup ), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
return
|
||||
case .tooMuchJoined:
|
||||
strongSelf.interfaceInteraction?.getNavigationController()?.pushViewController(oldChannelsController(context: context, intent: .join, completed: { value in
|
||||
if value {
|
||||
|
@ -2931,7 +2931,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
window.rootViewController?.present(controller, animated: true)
|
||||
}
|
||||
case .speak:
|
||||
let _ = speakText(text.string)
|
||||
let _ = speakText(context: strongSelf.context, text: text.string)
|
||||
case .translate:
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
|
||||
|
@ -152,7 +152,9 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
|
||||
isMember = true
|
||||
case .left:
|
||||
if case .replyThread = chatPresentationInterfaceState.chatLocation {
|
||||
isMember = true
|
||||
if !channel.flags.contains(.joinToSend) {
|
||||
isMember = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,16 +154,16 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
return true
|
||||
}
|
||||
case let .editExportedInvitation(_, invite), let .revokeExportedInvitation(invite), let .deleteExportedInvitation(invite), let .participantJoinedViaInvite(invite), let .participantJoinByRequest(invite, _):
|
||||
if !invite.link.hasSuffix("...") {
|
||||
if let inviteLink = invite.link, !inviteLink.hasSuffix("...") {
|
||||
if invite.isPermanent {
|
||||
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
|
||||
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ActionSheetTextItem(title: invite.link))
|
||||
items.append(ActionSheetTextItem(title: inviteLink))
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.InviteLink_ContextRevoke, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
if let strongSelf = self {
|
||||
let _ = (strongSelf.context.engine.peers.revokePeerExportedInvitation(peerId: peer.id, link: invite.link)
|
||||
let _ = (strongSelf.context.engine.peers.revokePeerExportedInvitation(peerId: peer.id, link: inviteLink)
|
||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||
self?.eventLogContext.reload()
|
||||
})
|
||||
|
@ -1275,7 +1275,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
var text: String = ""
|
||||
var entities: [MessageTextEntity] = []
|
||||
|
||||
let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_DeletedInviteLink(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", invite.link.replacingOccurrences(of: "https://", with: ""))
|
||||
let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_DeletedInviteLink(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", invite.link?.replacingOccurrences(of: "https://", with: "") ?? "")
|
||||
|
||||
appendAttributedText(text: rawText, generateEntities: { index in
|
||||
if index == 0, let author = author {
|
||||
@ -1301,7 +1301,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
var text: String = ""
|
||||
var entities: [MessageTextEntity] = []
|
||||
|
||||
let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_RevokedInviteLink(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", invite.link.replacingOccurrences(of: "https://", with: ""))
|
||||
let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_RevokedInviteLink(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", invite.link?.replacingOccurrences(of: "https://", with: "") ?? "")
|
||||
|
||||
appendAttributedText(text: rawText, generateEntities: { index in
|
||||
if index == 0, let author = author {
|
||||
@ -1327,7 +1327,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
var text: String = ""
|
||||
var entities: [MessageTextEntity] = []
|
||||
|
||||
let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_EditedInviteLink(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", updatedInvite.link.replacingOccurrences(of: "https://", with: ""))
|
||||
let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_EditedInviteLink(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", updatedInvite.link?.replacingOccurrences(of: "https://", with: "") ?? "")
|
||||
|
||||
appendAttributedText(text: rawText, generateEntities: { index in
|
||||
if index == 0, let author = author {
|
||||
@ -1353,7 +1353,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
var text: String = ""
|
||||
var entities: [MessageTextEntity] = []
|
||||
|
||||
let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_JoinedViaInviteLink(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", invite.link.replacingOccurrences(of: "https://", with: ""))
|
||||
let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_JoinedViaInviteLink(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", invite.link?.replacingOccurrences(of: "https://", with: "") ?? "")
|
||||
|
||||
appendAttributedText(text: rawText, generateEntities: { index in
|
||||
if index == 0, let author = author {
|
||||
@ -1478,7 +1478,14 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
var text: String = ""
|
||||
var entities: [MessageTextEntity] = []
|
||||
|
||||
let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_JoinedViaRequest(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", invite.link.replacingOccurrences(of: "https://", with: ""), approver.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "")
|
||||
let rawText: PresentationStrings.FormattedString
|
||||
switch invite {
|
||||
case let .link(link, _, _, _, _, _, _, _, _, _, _, _):
|
||||
rawText = self.presentationData.strings.Channel_AdminLog_JoinedViaRequest(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", link.replacingOccurrences(of: "https://", with: ""), approver.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "")
|
||||
case .publicJoinRequest:
|
||||
rawText = self.presentationData.strings.Channel_AdminLog_JoinedViaPublicRequest(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", approver.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "")
|
||||
}
|
||||
|
||||
|
||||
appendAttributedText(text: rawText, generateEntities: { index in
|
||||
if index == 0, let author = author {
|
||||
|
@ -2367,7 +2367,9 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
text = current.inputText.attributedSubstring(from: NSMakeRange(current.selectionRange.lowerBound, current.selectionRange.count)).string
|
||||
return (current, inputMode)
|
||||
}
|
||||
let _ = speakText(text)
|
||||
if let context = self.context {
|
||||
let _ = speakText(context: context, text: text)
|
||||
}
|
||||
|
||||
if #available(iOS 13.0, *) {
|
||||
UIMenuController.shared.hideMenu()
|
||||
|
@ -160,7 +160,7 @@ private final class TranslateScreenComponent: CombinedComponent {
|
||||
self.isSpeakingTranslatedText = false
|
||||
|
||||
self.isSpeakingOriginalText = true
|
||||
self.speechHolder = speakText(self.text)
|
||||
self.speechHolder = speakText(context: self.context, text: self.text)
|
||||
self.speechHolder?.completion = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -188,7 +188,7 @@ private final class TranslateScreenComponent: CombinedComponent {
|
||||
self.isSpeakingOriginalText = false
|
||||
|
||||
self.isSpeakingTranslatedText = true
|
||||
self.speechHolder = speakText(translatedText)
|
||||
self.speechHolder = speakText(context: self.context, text: translatedText)
|
||||
self.speechHolder?.completion = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
@implementation LottieInstance
|
||||
|
||||
- (instancetype _Nullable)initWithData:(NSData * _Nonnull)data fitzModifier:(LottieFitzModifier)fitzModifier cacheKey:(NSString * _Nonnull)cacheKey {
|
||||
- (instancetype _Nullable)initWithData:(NSData * _Nonnull)data fitzModifier:(LottieFitzModifier)fitzModifier colorReplacements:(NSDictionary * _Nullable)colorReplacements cacheKey:(NSString * _Nonnull)cacheKey {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
rlottie::FitzModifier modifier;
|
||||
@ -35,7 +35,15 @@
|
||||
break;
|
||||
}
|
||||
|
||||
_animation = rlottie::Animation::loadFromData(std::string(reinterpret_cast<const char *>(data.bytes), data.length), std::string([cacheKey UTF8String]), "", false, {}, modifier);
|
||||
std::vector<std::pair<std::uint32_t, std::uint32_t>> colorsVector;
|
||||
if (colorReplacements != nil) {
|
||||
for (NSNumber *color in colorReplacements.allKeys) {
|
||||
NSNumber *replacement = colorReplacements[color];
|
||||
colorsVector.push_back({ color.unsignedIntValue, replacement.unsignedIntValue });
|
||||
}
|
||||
}
|
||||
|
||||
_animation = rlottie::Animation::loadFromData(std::string(reinterpret_cast<const char *>(data.bytes), data.length), std::string([cacheKey UTF8String]), "", false, colorsVector, modifier);
|
||||
if (_animation == nullptr) {
|
||||
return nil;
|
||||
}
|
||||
|
@ -19,7 +19,8 @@ typedef NS_ENUM(int32_t, LottieFitzModifier) {
|
||||
@property (nonatomic, readonly) int32_t frameRate;
|
||||
@property (nonatomic, readonly) CGSize dimensions;
|
||||
|
||||
- (instancetype _Nullable)initWithData:(NSData * _Nonnull)data fitzModifier:(LottieFitzModifier)fitzModifier cacheKey:(NSString * _Nonnull)cacheKey;
|
||||
- (instancetype _Nullable)initWithData:(NSData * _Nonnull)data fitzModifier:(LottieFitzModifier)fitzModifier colorReplacements:(NSDictionary * _Nullable)colorReplacements cacheKey:(NSString * _Nonnull)cacheKey;
|
||||
|
||||
- (void)renderFrameWithIndex:(int32_t)index into:(uint8_t * _Nonnull)buffer width:(int32_t)width height:(int32_t)height bytesPerRow:(int32_t)bytesPerRow;
|
||||
|
||||
@end
|
||||
|
Loading…
x
Reference in New Issue
Block a user