Various improvements

This commit is contained in:
Ilya Laktyushin 2022-04-15 03:31:37 +04:00
parent df2354e9bb
commit 701fe95891
56 changed files with 1035 additions and 788 deletions

View File

@ -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))

View File

@ -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$@";

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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
}

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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))

View File

@ -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)

View File

@ -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 {

View File

@ -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

View File

@ -26,6 +26,7 @@ swift_library(
"//submodules/AccountContext:AccountContext",
"//submodules/AnimationUI:AnimationUI",
"//submodules/ShimmerEffect:ShimmerEffect",
"//submodules/ManagedAnimationNode:ManagedAnimationNode",
],
visibility = [
"//visibility:public",

View File

@ -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)

View File

@ -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)
}
}

View File

@ -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

View File

@ -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 ?? ""
}
}

View File

@ -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() {

View File

@ -11,6 +11,7 @@ swift_library(
],
deps = [
"//submodules/Display:Display",
"//submodules/AccountContext:AccountContext",
],
visibility = [
"//visibility:public",

View File

@ -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) {

View File

@ -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 }) {

View File

@ -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:

View File

@ -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

View File

@ -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()

View File

@ -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
}
}
}
}

View File

@ -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
}
}
}
}

View File

@ -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)

View File

@ -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()

View File

@ -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)

View File

@ -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 {

View File

@ -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)
}
}
}

View File

@ -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
}
}
}

View File

@ -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
}
}
}

View File

@ -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 {

View File

@ -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) {

View File

@ -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()
}
}
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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":[]}

View File

@ -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

View File

@ -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":[]}

View File

@ -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 {

View File

@ -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()

View File

@ -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
}
}
}

View File

@ -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()
})

View File

@ -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 {

View File

@ -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()

View File

@ -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

View File

@ -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;
}

View File

@ -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