mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-23 08:47:20 +00:00
Merge commit '5e79ec4b32e8c3c9c86216c9697fd40251ba3f2d'
This commit is contained in:
commit
93b421cd73
@ -13961,6 +13961,8 @@ Sorry for the inconvenience.";
|
||||
"PeerInfo.Gifts.ToastUnpinned.Text" = "Gift Unpinned.";
|
||||
"PeerInfo.Gifts.ToastPinned.Title" = "Gift Pinned";
|
||||
"PeerInfo.Gifts.ToastPinned.Text" = "Now it will always be shown on the top.";
|
||||
"PeerInfo.Gifts.ToastPinned.TitleNew" = "%@ Pinned";
|
||||
"PeerInfo.Gifts.ToastPinned.ReplacingText" = "replacing %@.";
|
||||
|
||||
"Chat.PaidMessage.Confirm.Title" = "Confirm Payment";
|
||||
"Chat.PaidMessage.Confirm.DontAskAgain" = "Don't ask again";
|
||||
@ -14034,3 +14036,56 @@ Sorry for the inconvenience.";
|
||||
"Privacy.Gifts.PremiumToast.Action" = "Open";
|
||||
|
||||
"Gift.Send.ErrorDisallowed" = "**%@** doesn't accept this kind of gifts.";
|
||||
|
||||
"ChatbotSetup.Rights.ManageMessages" = "Manage Messages";
|
||||
"ChatbotSetup.Rights.ReadMessages" = "Read Messages";
|
||||
"ChatbotSetup.Rights.ReplyToMessages" = "Reply to Messages";
|
||||
"ChatbotSetup.Rights.MarkAsRead" = "Mark Messages as Read";
|
||||
"ChatbotSetup.Rights.DeleteSentMessages" = "Delete Sent Messages";
|
||||
"ChatbotSetup.Rights.DeleteReceivedMessages" = "Delete Received Messages";
|
||||
|
||||
"ChatbotSetup.Rights.ManageProfile" = "Manage Profile";
|
||||
"ChatbotSetup.Rights.EditName" = "Edit Name";
|
||||
"ChatbotSetup.Rights.EditBio" = "Edit Bio";
|
||||
"ChatbotSetup.Rights.EditProfilePhoto" = "Edit Profile Photo";
|
||||
"ChatbotSetup.Rights.EditUsername" = "Edit Username";
|
||||
|
||||
"ChatbotSetup.Rights.ManageGiftsAndStars" = "Manage Gifts and Stars";
|
||||
"ChatbotSetup.Rights.ViewGifts" = "View Gifts";
|
||||
"ChatbotSetup.Rights.SellGifts" = "Sell Gifts";
|
||||
"ChatbotSetup.Rights.ChangeGiftSettings" = "Change Gift Settings";
|
||||
"ChatbotSetup.Rights.TransferAndUpgradeGifts" = "Transfer and Upgrade Gifts";
|
||||
"ChatbotSetup.Rights.TransferStars" = "Transfer Stars";
|
||||
"ChatbotSetup.Rights.ManageStories" = "Manage Stories";
|
||||
|
||||
"Gift.Send.Upgrade.ForcedInfo" = "%1$@ accepts only unique gifts. [Learn More >]()";
|
||||
|
||||
"Privacy.Gifts.ShowGiftButton" = "Show Gift Icon in Chats";
|
||||
"Privacy.Gifts.ShowGiftButtonInfo" = "Display the #Gift icon in the message input field for both participants in all chats.";
|
||||
|
||||
"Privacy.Gifts.AcceptedTypes" = "ACCEPTED GIFT TYPES";
|
||||
"Privacy.Gifts.AcceptedTypes.Unlimited" = "Unlimited";
|
||||
"Privacy.Gifts.AcceptedTypes.Limited" = "Limited-Edition";
|
||||
"Privacy.Gifts.AcceptedTypes.Unique" = "Unique";
|
||||
"Privacy.Gifts.AcceptedTypes.Premium" = "Premium Subscriptions";
|
||||
"Privacy.Gifts.AcceptedTypes.Info" = "Choose the types of gifts that you allow others to send you.";
|
||||
|
||||
"Chat.PanelFrozenAccount.Title" = "You account is frozen";
|
||||
"Chat.PanelFrozenAccount.Text" = "Tap to view details";
|
||||
|
||||
"FrozenAccount.Title" = "Your Account is Frozen";
|
||||
"FrozenAccount.Violation.Title" = "Violation of Terms";
|
||||
"FrozenAccount.Violation.Text" = "Your account was frozen for breaking Telegram's Terms and Conditions.";
|
||||
"FrozenAccount.ReadOnly.Title" = "Read-Only Mode";
|
||||
"FrozenAccount.ReadOnly.Text" = "You can access your account but can't send messages or take actions.";
|
||||
"FrozenAccount.Appeal.Title" = "Appeal Before Deactivation";
|
||||
"FrozenAccount.Appeal.Text" = "Appeal via [@SpamBot]() before %@, or your account will be deleted.";
|
||||
"FrozenAccount.SubmitAppeal" = "Submit an Appeal";
|
||||
"FrozenAccount.Understood" = "Understood";
|
||||
|
||||
"AdsInfo.Search.Respect.Text" = "Ads like this do not use your personal information and are based on the search query you entered.";
|
||||
"AdsInfo.Search.Ads.Text" = "You can turn off ads by subscribing to [Telegram Premium]().";
|
||||
"AdsInfo.Search.Launch.Text" = "Anyone can create an ad to display in search results for any query. Check out the Telegram Ad Platform for details. [Learn More >]()";
|
||||
|
||||
"ChatList.FrozenAccount.Title" = "Your account is frozen";
|
||||
"ChatList.FrozenAccount.Text" = "Tap to view details and submit an appeal.";
|
||||
|
||||
@ -11,6 +11,7 @@ public final class BotCheckoutController: ViewController {
|
||||
public final class InputData {
|
||||
public enum FetchError {
|
||||
case generic
|
||||
case disallowedStarGifts
|
||||
}
|
||||
|
||||
public let form: BotPaymentForm
|
||||
@ -53,8 +54,13 @@ public final class BotCheckoutController: ViewController {
|
||||
}
|
||||
|
||||
return context.engine.payments.fetchBotPaymentForm(source: source, themeParams: themeParams)
|
||||
|> mapError { _ -> FetchError in
|
||||
return .generic
|
||||
|> mapError { error -> FetchError in
|
||||
switch error {
|
||||
case .disallowedStarGift:
|
||||
return .disallowedStarGifts
|
||||
default:
|
||||
return .generic
|
||||
}
|
||||
}
|
||||
|> mapToSignal { paymentForm -> Signal<InputData, FetchError> in
|
||||
let botPeer: Signal<EnginePeer?, FetchError>
|
||||
|
||||
@ -114,6 +114,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/LottieComponent",
|
||||
"//submodules/TelegramUI/Components/AvatarUploadToastScreen",
|
||||
"//submodules/TelegramUI/Components/Ads/AdsInfoScreen",
|
||||
"//submodules/TelegramUI/Components/Ads/AdsReportScreen",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
||||
@ -54,6 +54,7 @@ import OldChannelsController
|
||||
import TextFormat
|
||||
import AvatarUploadToastScreen
|
||||
import AdsInfoScreen
|
||||
import AdsReportScreen
|
||||
|
||||
private final class ContextControllerContentSourceImpl: ContextControllerContentSource {
|
||||
let controller: ViewController
|
||||
@ -3935,13 +3936,13 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
}
|
||||
|
||||
if resetCurrentEntry {
|
||||
strongSelf.selectTab(id: selectedEntryId)
|
||||
strongSelf.selectTab(id: selectedEntryId, switchToChatsIfNeeded: false)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
private func selectTab(id: ChatListFilterTabEntryId) {
|
||||
if self.parent == nil {
|
||||
private func selectTab(id: ChatListFilterTabEntryId, switchToChatsIfNeeded: Bool = true) {
|
||||
if self.parent == nil, switchToChatsIfNeeded {
|
||||
if let navigationController = self.context.sharedContext.mainWindow?.viewController as? NavigationController {
|
||||
for controller in navigationController.viewControllers {
|
||||
if let controller = controller as? TabBarController {
|
||||
@ -6131,7 +6132,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
self.push(controller)
|
||||
}
|
||||
|
||||
func openAdInfo(_ node: ASDisplayNode) {
|
||||
func openAdInfo(node: ASDisplayNode, adPeer: AdPeer) {
|
||||
let controller = self
|
||||
let referenceView = node.view
|
||||
|
||||
@ -6139,7 +6140,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
var actions: [ContextMenuItem] = []
|
||||
//if adAttribute.sponsorInfo != nil || adAttribute.additionalInfo != nil {
|
||||
if adPeer.sponsorInfo != nil || adPeer.additionalInfo != nil {
|
||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ContextMenu_AdSponsorInfo, textColor: .primary, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Channels"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconSource: nil, action: { [weak self] c, _ in
|
||||
@ -6154,34 +6155,42 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
|
||||
subItems.append(.separator)
|
||||
|
||||
// if let sponsorInfo = adAttribute.sponsorInfo {
|
||||
// subItems.append(.action(ContextMenuActionItem(text: sponsorInfo, textColor: .primary, textLayout: .multiline, textFont: .custom(font: Font.regular(floor(presentationData.listsFontSize.baseDisplaySize * 0.8)), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
// return nil
|
||||
// }, iconSource: nil, action: { [weak self] c, _ in
|
||||
// c?.dismiss(completion: {
|
||||
// UIPasteboard.general.string = sponsorInfo
|
||||
//
|
||||
// self?.displayUndo(.copy(text: presentationData.strings.Chat_ContextMenu_AdSponsorInfoCopied))
|
||||
// })
|
||||
// })))
|
||||
// }
|
||||
// if let additionalInfo = adAttribute.additionalInfo {
|
||||
// subItems.append(.action(ContextMenuActionItem(text: additionalInfo, textColor: .primary, textLayout: .multiline, textFont: .custom(font: Font.regular(floor(presentationData.listsFontSize.baseDisplaySize * 0.8)), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
// return nil
|
||||
// }, iconSource: nil, action: { [weak self] c, _ in
|
||||
// c?.dismiss(completion: {
|
||||
// UIPasteboard.general.string = additionalInfo
|
||||
//
|
||||
// self?.displayUndo(.copy(text: presentationData.strings.Chat_ContextMenu_AdSponsorInfoCopied))
|
||||
// })
|
||||
// })))
|
||||
// }
|
||||
if let sponsorInfo = adPeer.sponsorInfo {
|
||||
subItems.append(.action(ContextMenuActionItem(text: sponsorInfo, textColor: .primary, textLayout: .multiline, textFont: .custom(font: Font.regular(floor(presentationData.listsFontSize.baseDisplaySize * 0.8)), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return nil
|
||||
}, iconSource: nil, action: { [weak self] c, _ in
|
||||
c?.dismiss(completion: {
|
||||
UIPasteboard.general.string = sponsorInfo
|
||||
|
||||
if let self {
|
||||
self.present(UndoOverlayController(presentationData: presentationData, content: .copy(text: presentationData.strings.Chat_ContextMenu_AdSponsorInfoCopied), elevatedLayout: false, action: { _ in
|
||||
return true
|
||||
}), in: .current)
|
||||
}
|
||||
})
|
||||
})))
|
||||
}
|
||||
if let additionalInfo = adPeer.additionalInfo {
|
||||
subItems.append(.action(ContextMenuActionItem(text: additionalInfo, textColor: .primary, textLayout: .multiline, textFont: .custom(font: Font.regular(floor(presentationData.listsFontSize.baseDisplaySize * 0.8)), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return nil
|
||||
}, iconSource: nil, action: { [weak self] c, _ in
|
||||
c?.dismiss(completion: {
|
||||
UIPasteboard.general.string = additionalInfo
|
||||
|
||||
if let self {
|
||||
self.present(UndoOverlayController(presentationData: presentationData, content: .copy(text: presentationData.strings.Chat_ContextMenu_AdSponsorInfoCopied), elevatedLayout: false, action: { _ in
|
||||
return true
|
||||
}), in: .current)
|
||||
}
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
||||
c?.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
})))
|
||||
//}
|
||||
}
|
||||
|
||||
actions.append(.action(ContextMenuActionItem(text: "About These Ads", textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ContextMenu_AboutAd, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Info"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconSource: nil, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
@ -6190,70 +6199,59 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
}
|
||||
})))
|
||||
|
||||
if "".isEmpty {
|
||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ContextMenu_ReportAd, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Restrict"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconSource: nil, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
guard let navigationController = self?.navigationController as? NavigationController else {
|
||||
return
|
||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ContextMenu_ReportAd, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Restrict"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconSource: nil, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
guard let navigationController = self?.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
|
||||
let _ = (context.engine.messages.reportAdMessage(opaqueId: adPeer.opaqueId, option: nil)
|
||||
|> deliverOnMainQueue).start(next: { [weak navigationController] result in
|
||||
if case let .options(title, options) = result {
|
||||
Queue.mainQueue().after(0.2) {
|
||||
navigationController?.pushViewController(
|
||||
AdsReportScreen(
|
||||
context: context,
|
||||
opaqueId: adPeer.opaqueId,
|
||||
title: title,
|
||||
options: options,
|
||||
completed: {
|
||||
//removeAd?(adAttribute.opaqueId)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
let _ = navigationController
|
||||
//.dismiss(animated: true)
|
||||
|
||||
// let _ = (context.engine.messages.reportAdMessage(peerId: message.id.peerId, opaqueId: adAttribute.opaqueId, option: nil)
|
||||
// |> deliverOnMainQueue).start(next: { [weak navigationController] result in
|
||||
// if case let .options(title, options) = result {
|
||||
// Queue.mainQueue().after(0.2) {
|
||||
// navigationController?.pushViewController(
|
||||
// AdsReportScreen(
|
||||
// context: context,
|
||||
// peerId: message.id.peerId,
|
||||
// opaqueId: adAttribute.opaqueId,
|
||||
// title: title,
|
||||
// options: options,
|
||||
// completed: {
|
||||
// removeAd?(adAttribute.opaqueId)
|
||||
// }
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
})))
|
||||
|
||||
actions.append(.separator)
|
||||
|
||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ContextMenu_RemoveAd, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconSource: nil, action: { [weak self] c, _ in
|
||||
c?.dismiss(completion: {
|
||||
let _ = self
|
||||
// if context.isPremium {
|
||||
// removeAd?(adAttribute.opaqueId)
|
||||
// } else {
|
||||
// self?.presentNoAdsDemo()
|
||||
// }
|
||||
})
|
||||
})))
|
||||
}
|
||||
// } else {
|
||||
// if !actions.isEmpty {
|
||||
// actions.append(.separator)
|
||||
// }
|
||||
// actions.append(.action(ContextMenuActionItem(text: presentationData.strings.SponsoredMessageMenu_Hide, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
// return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.primaryTextColor)
|
||||
// }, iconSource: nil, action: { [weak self] c, _ in
|
||||
// c?.dismiss(completion: {
|
||||
// if context.isPremium {
|
||||
// removeAd?(adAttribute.opaqueId)
|
||||
// } else {
|
||||
// self?.presentNoAdsDemo()
|
||||
// }
|
||||
// })
|
||||
// })))
|
||||
// }
|
||||
})
|
||||
})))
|
||||
|
||||
actions.append(.separator)
|
||||
|
||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ContextMenu_RemoveAd, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconSource: nil, action: { [weak self] c, _ in
|
||||
guard let navigationController = self?.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
c?.dismiss(completion: {
|
||||
if context.isPremium && !"".isEmpty {
|
||||
//removeAd?(adAttribute.opaqueId)
|
||||
} else {
|
||||
var replaceImpl: ((ViewController) -> Void)?
|
||||
let demoController = context.sharedContext.makePremiumDemoController(context: context, subject: .noAds, forceDark: false, action: {
|
||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .ads, forceDark: false, dismissed: nil)
|
||||
replaceImpl?(controller)
|
||||
}, dismissed: nil)
|
||||
replaceImpl = { [weak demoController] c in
|
||||
demoController?.replace(with: c)
|
||||
}
|
||||
navigationController.pushViewController(demoController)
|
||||
}
|
||||
})
|
||||
})))
|
||||
|
||||
let contextController = ContextController(presentationData: presentationData, source: .reference(AdsInfoContextReferenceContentSource(controller: controller, sourceView: referenceView, insets: .zero, contentInsets: .zero)), items: .single(ContextController.Items(content: .list(actions))), gesture: nil)
|
||||
controller.presentInGlobalOverlay(contextController)
|
||||
@ -6310,6 +6308,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
}
|
||||
|
||||
var isStoryPostingAvailable: Bool {
|
||||
guard !self.context.isFrozen else {
|
||||
return false
|
||||
}
|
||||
switch self.storyPostingAvailability {
|
||||
case .enabled:
|
||||
return true
|
||||
|
||||
@ -1684,8 +1684,8 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
|
||||
contentNode.dismissSearch = { [weak self] in
|
||||
self?.dismissSearch?()
|
||||
}
|
||||
contentNode.openAdInfo = { [weak self] node in
|
||||
self?.controller?.openAdInfo(node)
|
||||
contentNode.openAdInfo = { [weak self] node, adPeer in
|
||||
self?.controller?.openAdInfo(node: node, adPeer: adPeer)
|
||||
}
|
||||
|
||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, contentNode: contentNode, cancel: { [weak self] in
|
||||
|
||||
@ -62,9 +62,9 @@ final class ChatListSearchInteraction {
|
||||
let openStories: ((PeerId, ASDisplayNode) -> Void)?
|
||||
let switchToFilter: (ChatListSearchPaneKey) -> Void
|
||||
let dismissSearch: () -> Void
|
||||
let openAdInfo: (ASDisplayNode) -> Void
|
||||
let openAdInfo: (ASDisplayNode, AdPeer) -> Void
|
||||
|
||||
init(openPeer: @escaping (EnginePeer, EnginePeer?, Int64?, Bool) -> Void, openDisabledPeer: @escaping (EnginePeer, Int64?, ChatListDisabledPeerReason) -> Void, openMessage: @escaping (EnginePeer, Int64?, EngineMessage.Id, Bool) -> Void, openUrl: @escaping (String) -> Void, clearRecentSearch: @escaping () -> Void, addContact: @escaping (String) -> Void, toggleMessageSelection: @escaping (EngineMessage.Id, Bool) -> Void, messageContextAction: @escaping ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?, ChatListSearchPaneKey, (id: String, size: Int64, isFirstInList: Bool)?) -> Void), mediaMessageContextAction: @escaping ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void), peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, getSelectedMessageIds: @escaping () -> Set<EngineMessage.Id>?, openStories: ((PeerId, ASDisplayNode) -> Void)?, switchToFilter: @escaping (ChatListSearchPaneKey) -> Void, dismissSearch: @escaping () -> Void, openAdInfo: @escaping (ASDisplayNode) -> Void) {
|
||||
init(openPeer: @escaping (EnginePeer, EnginePeer?, Int64?, Bool) -> Void, openDisabledPeer: @escaping (EnginePeer, Int64?, ChatListDisabledPeerReason) -> Void, openMessage: @escaping (EnginePeer, Int64?, EngineMessage.Id, Bool) -> Void, openUrl: @escaping (String) -> Void, clearRecentSearch: @escaping () -> Void, addContact: @escaping (String) -> Void, toggleMessageSelection: @escaping (EngineMessage.Id, Bool) -> Void, messageContextAction: @escaping ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?, ChatListSearchPaneKey, (id: String, size: Int64, isFirstInList: Bool)?) -> Void), mediaMessageContextAction: @escaping ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void), peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, getSelectedMessageIds: @escaping () -> Set<EngineMessage.Id>?, openStories: ((PeerId, ASDisplayNode) -> Void)?, switchToFilter: @escaping (ChatListSearchPaneKey) -> Void, dismissSearch: @escaping () -> Void, openAdInfo: @escaping (ASDisplayNode, AdPeer) -> Void) {
|
||||
self.openPeer = openPeer
|
||||
self.openDisabledPeer = openDisabledPeer
|
||||
self.openMessage = openMessage
|
||||
@ -105,7 +105,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
private let navigationController: NavigationController?
|
||||
|
||||
var dismissSearch: (() -> Void)?
|
||||
var openAdInfo: ((ASDisplayNode) -> Void)?
|
||||
var openAdInfo: ((ASDisplayNode, AdPeer) -> Void)?
|
||||
|
||||
private let dimNode: ASDisplayNode
|
||||
let filterContainerNode: ChatListSearchFiltersContainerNode
|
||||
@ -307,8 +307,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
}
|
||||
}, dismissSearch: { [weak self] in
|
||||
self?.dismissSearch?()
|
||||
}, openAdInfo: { [weak self] node in
|
||||
self?.openAdInfo?(node)
|
||||
}, openAdInfo: { [weak self] node, adPeer in
|
||||
self?.openAdInfo?(node, adPeer)
|
||||
})
|
||||
self.paneContainerNode.interaction = interaction
|
||||
|
||||
|
||||
@ -439,8 +439,9 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
|
||||
case topic(EnginePeer, ChatListItemContent.ThreadInfo, Int, PresentationTheme, PresentationStrings, ChatListSearchSectionExpandType)
|
||||
case recentlySearchedPeer(EnginePeer, EnginePeer?, (Int32, Bool)?, Int, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder, PeerStoryStats?, Bool)
|
||||
case adPeer(AdPeer, Int, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder, ChatListSearchSectionExpandType, String?)
|
||||
case localPeer(EnginePeer, EnginePeer?, (Int32, Bool)?, Int, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder, ChatListSearchSectionExpandType, PeerStoryStats?, Bool, Bool)
|
||||
case globalPeer(FoundPeer, (Int32, Bool)?, Int, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder, ChatListSearchSectionExpandType, PeerStoryStats?, Bool, String?, Bool)
|
||||
case globalPeer(FoundPeer, (Int32, Bool)?, Int, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder, ChatListSearchSectionExpandType, PeerStoryStats?, Bool, String?)
|
||||
case message(EngineMessage, EngineRenderedPeer, EnginePeerReadCounters?, EngineMessageHistoryThread.Info?, ChatListPresentationData, Int32, Bool?, Bool, MessageOrderingKey, (id: String, size: Int64, isFirstInList: Bool)?, MessageSection, Bool, PeerStoryStats?, Bool, TelegramSearchPeersScope)
|
||||
case messagePlaceholder(Int32, ChatListPresentationData, TelegramSearchPeersScope)
|
||||
case emptyMessagesFooter(ChatListPresentationData, TelegramSearchPeersScope, String?)
|
||||
@ -454,7 +455,9 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
return .localPeerId(peer.id)
|
||||
case let .localPeer(peer, _, _, _, _, _, _, _, _, _, _, _):
|
||||
return .localPeerId(peer.id)
|
||||
case let .globalPeer(peer, _, _, _, _, _, _, _, _, _, _, _):
|
||||
case let .adPeer(peer, _, _, _, _, _, _, _):
|
||||
return .globalPeerId(peer.peer.id)
|
||||
case let .globalPeer(peer, _, _, _, _, _, _, _, _, _, _):
|
||||
return .globalPeerId(peer.peer.id)
|
||||
case let .message(message, _, _, _, _, _, _, _, _, _, section, _, _, _, _):
|
||||
return .messageId(message.id, section)
|
||||
@ -487,8 +490,14 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .globalPeer(lhsPeer, lhsUnreadBadge, lhsIndex, lhsTheme, lhsStrings, lhsSortOrder, lhsDisplayOrder, lhsExpandType, lhsStoryStats, lhsRequiresPremiumForMessaging, lhsQuery, lhsIsAd):
|
||||
if case let .globalPeer(rhsPeer, rhsUnreadBadge, rhsIndex, rhsTheme, rhsStrings, rhsSortOrder, rhsDisplayOrder, rhsExpandType, rhsStoryStats, rhsRequiresPremiumForMessaging, rhsQuery, rhsIsAd) = rhs, lhsPeer == rhsPeer && lhsIndex == rhsIndex && lhsTheme === rhsTheme && lhsStrings === rhsStrings && lhsSortOrder == rhsSortOrder && lhsDisplayOrder == rhsDisplayOrder && lhsUnreadBadge?.0 == rhsUnreadBadge?.0 && lhsUnreadBadge?.1 == rhsUnreadBadge?.1 && lhsExpandType == rhsExpandType && lhsStoryStats == rhsStoryStats && lhsRequiresPremiumForMessaging == rhsRequiresPremiumForMessaging, lhsQuery == rhsQuery, lhsIsAd == rhsIsAd {
|
||||
case let .adPeer(lhsPeer, lhsIndex, lhsTheme, lhsStrings, lhsSortOrder, lhsDisplayOrder, lhsExpandType, lhsQuery):
|
||||
if case let .adPeer(rhsPeer, rhsIndex, rhsTheme, rhsStrings, rhsSortOrder, rhsDisplayOrder, rhsExpandType, rhsQuery) = rhs, lhsPeer == rhsPeer && lhsIndex == rhsIndex && lhsTheme === rhsTheme && lhsStrings === rhsStrings && lhsSortOrder == rhsSortOrder && lhsDisplayOrder == rhsDisplayOrder && lhsExpandType == rhsExpandType && lhsQuery == rhsQuery {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .globalPeer(lhsPeer, lhsUnreadBadge, lhsIndex, lhsTheme, lhsStrings, lhsSortOrder, lhsDisplayOrder, lhsExpandType, lhsStoryStats, lhsRequiresPremiumForMessaging, lhsQuery):
|
||||
if case let .globalPeer(rhsPeer, rhsUnreadBadge, rhsIndex, rhsTheme, rhsStrings, rhsSortOrder, rhsDisplayOrder, rhsExpandType, rhsStoryStats, rhsRequiresPremiumForMessaging, rhsQuery) = rhs, lhsPeer == rhsPeer && lhsIndex == rhsIndex && lhsTheme === rhsTheme && lhsStrings === rhsStrings && lhsSortOrder == rhsSortOrder && lhsDisplayOrder == rhsDisplayOrder && lhsUnreadBadge?.0 == rhsUnreadBadge?.0 && lhsUnreadBadge?.1 == rhsUnreadBadge?.1 && lhsExpandType == rhsExpandType && lhsStoryStats == rhsStoryStats && lhsRequiresPremiumForMessaging == rhsRequiresPremiumForMessaging, lhsQuery == rhsQuery {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -620,14 +629,23 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
return false
|
||||
case let .localPeer(_, _, _, rhsIndex, _, _, _, _, _, _, _, _):
|
||||
return lhsIndex <= rhsIndex
|
||||
case .globalPeer, .message, .messagePlaceholder, .emptyMessagesFooter, .addContact:
|
||||
case .adPeer, .globalPeer, .message, .messagePlaceholder, .emptyMessagesFooter, .addContact:
|
||||
return true
|
||||
}
|
||||
case let .globalPeer(_, _, lhsIndex, _, _, _, _, _, _, _, _, _):
|
||||
case let .adPeer(_, lhsIndex, _, _, _, _, _, _):
|
||||
switch rhs {
|
||||
case .topic, .recentlySearchedPeer, .localPeer:
|
||||
return false
|
||||
case let .globalPeer(_, _, rhsIndex, _, _, _, _, _, _, _, _, _):
|
||||
case let .adPeer(_, rhsIndex, _, _, _, _, _, _):
|
||||
return lhsIndex <= rhsIndex
|
||||
case .globalPeer, .message, .messagePlaceholder, .emptyMessagesFooter, .addContact:
|
||||
return true
|
||||
}
|
||||
case let .globalPeer(_, _, lhsIndex, _, _, _, _, _, _, _, _):
|
||||
switch rhs {
|
||||
case .topic, .recentlySearchedPeer, .localPeer, .adPeer:
|
||||
return false
|
||||
case let .globalPeer(_, _, rhsIndex, _, _, _, _, _, _, _, _):
|
||||
return lhsIndex <= rhsIndex
|
||||
case .message, .messagePlaceholder, .emptyMessagesFooter, .addContact:
|
||||
return true
|
||||
@ -808,6 +826,52 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
openStories(peer.id, sourceNode.avatarNode)
|
||||
}
|
||||
})
|
||||
case let .adPeer(peer, _, theme, strings, nameSortOrder, nameDisplayOrder, expandType, _):
|
||||
let enabled = true
|
||||
var suffixString = ""
|
||||
if let subscribers = peer.subscribers, subscribers != 0 {
|
||||
if case .user = peer.peer {
|
||||
suffixString = ", \(strings.Conversation_StatusBotSubscribers(subscribers))"
|
||||
} else if case let .channel(channel) = peer.peer, case .broadcast = channel.info {
|
||||
suffixString = ", \(strings.Conversation_StatusSubscribers(subscribers))"
|
||||
} else {
|
||||
suffixString = ", \(strings.Conversation_StatusMembers(subscribers))"
|
||||
}
|
||||
}
|
||||
|
||||
let header: ChatListSearchItemHeader?
|
||||
let actionTitle: String?
|
||||
switch expandType {
|
||||
case .none:
|
||||
actionTitle = nil
|
||||
case .expand:
|
||||
actionTitle = strings.ChatList_Search_ShowMore
|
||||
case .collapse:
|
||||
actionTitle = strings.ChatList_Search_ShowLess
|
||||
}
|
||||
header = ChatListSearchItemHeader(type: .globalPeers, theme: theme, strings: strings, actionTitle: actionTitle, action: actionTitle == nil ? nil : { _ in
|
||||
toggleExpandGlobalResults()
|
||||
})
|
||||
|
||||
return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch(isSavedMessages: false), peer: .peer(peer: peer.peer, chatPeer: peer.peer), status: .addressName(suffixString), badge: nil, requiresPremiumForMessaging: false, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, searchQuery: nil, isAd: true, action: { _ in
|
||||
interaction.peerSelected(peer.peer, nil, nil, nil, false)
|
||||
context.engine.messages.markAdAction(opaqueId: peer.opaqueId, media: false, fullscreen: false)
|
||||
}, disabledAction: { _ in
|
||||
interaction.disabledPeerSelected(peer.peer, nil, .generic)
|
||||
}, contextAction: peerContextAction.flatMap { peerContextAction in
|
||||
return { node, gesture, location in
|
||||
peerContextAction(peer.peer, .search(nil), node, gesture, location)
|
||||
}
|
||||
}, animationCache: interaction.animationCache, animationRenderer: interaction.animationRenderer, storyStats: nil, openStories: { itemPeer, sourceNode in
|
||||
guard case let .peer(_, chatPeer) = itemPeer, let peer = chatPeer else {
|
||||
return
|
||||
}
|
||||
if let sourceNode = sourceNode as? ContactsPeerItemNode {
|
||||
openStories(peer.id, sourceNode.avatarNode)
|
||||
}
|
||||
}, adButtonAction: { node in
|
||||
interaction.openAdInfo(node, peer)
|
||||
})
|
||||
case let .localPeer(peer, associatedPeer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder, expandType, storyStats, requiresPremiumForMessaging, isSelf):
|
||||
let primaryPeer: EnginePeer
|
||||
var chatPeer: EnginePeer?
|
||||
@ -942,7 +1006,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
openStories(peer.id, sourceNode.avatarNode)
|
||||
}
|
||||
})
|
||||
case let .globalPeer(peer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder, expandType, storyStats, requiresPremiumForMessaging, query, isAd):
|
||||
case let .globalPeer(peer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder, expandType, storyStats, requiresPremiumForMessaging, query):
|
||||
var enabled = true
|
||||
if filter.contains(.onlyWriteable) {
|
||||
enabled = canSendMessagesToPeer(peer.peer)
|
||||
@ -1002,7 +1066,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
isSavedMessages = true
|
||||
}
|
||||
|
||||
return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch(isSavedMessages: isSavedMessages), peer: .peer(peer: EnginePeer(peer.peer), chatPeer: EnginePeer(peer.peer)), status: .addressName(suffixString), badge: badge, requiresPremiumForMessaging: requiresPremiumForMessaging, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, searchQuery: query, isAd: isAd, action: { _ in
|
||||
return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch(isSavedMessages: isSavedMessages), peer: .peer(peer: EnginePeer(peer.peer), chatPeer: EnginePeer(peer.peer)), status: .addressName(suffixString), badge: badge, requiresPremiumForMessaging: requiresPremiumForMessaging, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, searchQuery: query, isAd: false, action: { _ in
|
||||
interaction.peerSelected(EnginePeer(peer.peer), nil, nil, nil, false)
|
||||
}, disabledAction: { _ in
|
||||
interaction.disabledPeerSelected(EnginePeer(peer.peer), nil, requiresPremiumForMessaging ? .premiumRequired : .generic)
|
||||
@ -1019,8 +1083,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
if let sourceNode = sourceNode as? ContactsPeerItemNode {
|
||||
openStories(peer.id, sourceNode.avatarNode)
|
||||
}
|
||||
}, adButtonAction: { node in
|
||||
interaction.openAdInfo(node)
|
||||
}, adButtonAction: { _ in
|
||||
})
|
||||
case let .message(message, peer, readState, threadInfo, presentationData, _, selected, displayCustomHeader, orderingKey, _, section, allPaused, storyStats, requiresPremiumForMessaging, searchScope):
|
||||
let header: ChatListSearchItemHeader
|
||||
@ -1791,7 +1854,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
self.mediaNode.isHidden = true
|
||||
self.recentListNode.isHidden = peersFilter.contains(.excludeRecent)
|
||||
|
||||
let currentRemotePeers = Atomic<([FoundPeer], [FoundPeer])?>(value: nil)
|
||||
let currentRemotePeers = Atomic<([FoundPeer], [FoundPeer], [AdPeer])?>(value: nil)
|
||||
let presentationDataPromise = self.presentationDataPromise
|
||||
let searchStatePromise = self.searchStatePromise
|
||||
let selectionPromise = self.selectedMessagesPromise
|
||||
@ -2351,35 +2414,40 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
let _ = previousRecentlySearchedPeersState.swap(nil)
|
||||
}
|
||||
|
||||
let foundRemotePeers: Signal<([FoundPeer], [FoundPeer], Bool), NoError>
|
||||
let currentRemotePeersValue: ([FoundPeer], [FoundPeer]) = currentRemotePeers.with { $0 } ?? ([], [])
|
||||
let foundRemotePeers: Signal<([FoundPeer], [FoundPeer], [AdPeer], Bool), NoError>
|
||||
let currentRemotePeersValue: ([FoundPeer], [FoundPeer], [AdPeer]) = currentRemotePeers.with { $0 } ?? ([], [], [])
|
||||
if case .savedMessagesChats = location {
|
||||
foundRemotePeers = .single(([], [], false))
|
||||
foundRemotePeers = .single(([], [], [], false))
|
||||
} else if let query = query, case .chats = key {
|
||||
if query.hasPrefix("#") {
|
||||
foundRemotePeers = .single(([], [], false))
|
||||
foundRemotePeers = .single(([], [], [], false))
|
||||
} else {
|
||||
foundRemotePeers = (
|
||||
.single((currentRemotePeersValue.0, currentRemotePeersValue.1, true))
|
||||
.single((currentRemotePeersValue.0, currentRemotePeersValue.1, currentRemotePeersValue.2, true))
|
||||
|> then(
|
||||
globalPeerSearchContext.searchRemotePeers(engine: context.engine, query: query)
|
||||
|> map { ($0.0, $0.1, false) }
|
||||
|> mapToSignal { result in
|
||||
return context.engine.peers.searchAdPeers(query: query)
|
||||
|> map { adPeers in
|
||||
return (result.0, result.1, adPeers, false)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
} else if let query = query, case .channels = key {
|
||||
foundRemotePeers = (
|
||||
.single((currentRemotePeersValue.0, currentRemotePeersValue.1, true))
|
||||
.single((currentRemotePeersValue.0, currentRemotePeersValue.1, currentRemotePeersValue.2, true))
|
||||
|> then(
|
||||
globalPeerSearchContext.searchRemotePeers(engine: context.engine, query: query, scope: .channels)
|
||||
|> map { ($0.0, $0.1, false) }
|
||||
|> map { ($0.0, $0.1, [], false) }
|
||||
)
|
||||
)
|
||||
} else if let query, case .apps = key {
|
||||
let _ = query
|
||||
foundRemotePeers = .single(([], [], false))
|
||||
foundRemotePeers = .single(([], [], [], false))
|
||||
} else {
|
||||
foundRemotePeers = .single(([], [], false))
|
||||
foundRemotePeers = .single(([], [], [], false))
|
||||
}
|
||||
let searchLocations: [SearchMessagesLocation]
|
||||
if let options = options {
|
||||
@ -2661,7 +2729,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
foundThreads
|
||||
)
|
||||
|> map { accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, foundPublicMessages, presentationData, searchState, selectionState, resolvedMessage, recentPeers, allAndFoundThreads -> ([ChatListSearchEntry], Bool)? in
|
||||
let isSearching = foundRemotePeers.2 || foundRemoteMessages.1 || foundPublicMessages.1
|
||||
let isSearching = foundRemotePeers.3 || foundRemoteMessages.1 || foundPublicMessages.1
|
||||
var entries: [ChatListSearchEntry] = []
|
||||
var index = 0
|
||||
|
||||
@ -2677,7 +2745,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
recentPeers = []
|
||||
}
|
||||
|
||||
let _ = currentRemotePeers.swap((foundRemotePeers.0, foundRemotePeers.1))
|
||||
let _ = currentRemotePeers.swap((foundRemotePeers.0, foundRemotePeers.1, foundRemotePeers.2))
|
||||
|
||||
let filteredPeer: (EnginePeer, EnginePeer) -> Bool = { peer, accountPeer in
|
||||
if let requestPeerType {
|
||||
@ -2882,7 +2950,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if peersFilter.contains(.includeSelf) {
|
||||
for renderedPeer in foundLocalPeers.peers {
|
||||
if renderedPeer.peerId == context.account.peerId, let peer = renderedPeer.peers[renderedPeer.peerId], filteredPeer(peer, EnginePeer(accountPeer)) {
|
||||
@ -2962,7 +3030,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for peer in foundRemotePeers.0 {
|
||||
if case .expand = localExpandType, numberOfLocalPeers >= 3 {
|
||||
break
|
||||
@ -2978,6 +3046,14 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
|
||||
var numberOfGlobalPeers = 0
|
||||
index = 0
|
||||
for peer in foundRemotePeers.2 {
|
||||
if !existingPeerIds.contains(peer.peer.id) {
|
||||
existingPeerIds.insert(peer.peer.id)
|
||||
entries.append(.adPeer(peer, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, globalExpandType, finalQuery))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
if let _ = tagMask {
|
||||
} else {
|
||||
for peer in foundRemotePeers.1 {
|
||||
@ -2986,14 +3062,8 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
}
|
||||
|
||||
if !existingPeerIds.contains(peer.peer.id), filteredPeer(EnginePeer(peer.peer), EnginePeer(accountPeer)) {
|
||||
//TODO:unmock
|
||||
var isAd = !"".isEmpty
|
||||
#if DEBUG
|
||||
isAd = numberOfGlobalPeers == 0
|
||||
#endif
|
||||
|
||||
existingPeerIds.insert(peer.peer.id)
|
||||
entries.append(.globalPeer(peer, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, globalExpandType, nil, false, finalQuery, isAd))
|
||||
entries.append(.globalPeer(peer, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, globalExpandType, nil, false, finalQuery))
|
||||
index += 1
|
||||
numberOfGlobalPeers += 1
|
||||
}
|
||||
@ -3013,7 +3083,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
}
|
||||
|
||||
var firstHeaderId: Int64?
|
||||
if !foundRemotePeers.2 {
|
||||
if !foundRemotePeers.3 {
|
||||
index = 0
|
||||
var existingPostIds = Set<MessageId>()
|
||||
for foundPublicMessageSet in foundPublicMessages.0 {
|
||||
@ -3279,8 +3349,8 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
}, editPeer: { _ in
|
||||
}, openWebApp: { _ in
|
||||
}, openPhotoSetup: {
|
||||
}, openAdInfo: { node in
|
||||
interaction.openAdInfo(node)
|
||||
}, openAdInfo: { node, adPeer in
|
||||
interaction.openAdInfo(node, adPeer)
|
||||
}, openAccountFreezeInfo: {
|
||||
})
|
||||
chatListInteraction.isSearchMode = true
|
||||
@ -3410,7 +3480,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
if case let .user(user) = peer, user.flags.contains(.requirePremium) {
|
||||
requiresPremiumForMessagingPeerIds.append(peer.id)
|
||||
}
|
||||
case let .globalPeer(foundPeer, _, _, _, _, _, _, _, _, _, _, _):
|
||||
case let .globalPeer(foundPeer, _, _, _, _, _, _, _, _, _, _):
|
||||
storyStatsIds.append(foundPeer.peer.id)
|
||||
if let user = foundPeer.peer as? TelegramUser, user.flags.contains(.requirePremium) {
|
||||
requiresPremiumForMessagingPeerIds.append(foundPeer.peer.id)
|
||||
@ -3451,8 +3521,8 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
mappedItems[i] = .recentlySearchedPeer(peer, associatedPeer, unreadBadge, index, theme, strings, sortOrder, displayOrder, stats[peer.id] ?? nil, requiresPremiumForMessaging[peer.id] ?? false)
|
||||
case let .localPeer(peer, associatedPeer, unreadBadge, index, theme, strings, sortOrder, displayOrder, expandType, _, _, isSelf):
|
||||
mappedItems[i] = .localPeer(peer, associatedPeer, unreadBadge, index, theme, strings, sortOrder, displayOrder, expandType, stats[peer.id] ?? nil, requiresPremiumForMessaging[peer.id] ?? false, isSelf)
|
||||
case let .globalPeer(peer, unreadBadge, index, theme, strings, sortOrder, displayOrder, expandType, _, _, searchQuery, isAd):
|
||||
mappedItems[i] = .globalPeer(peer, unreadBadge, index, theme, strings, sortOrder, displayOrder, expandType, stats[peer.peer.id] ?? nil, requiresPremiumForMessaging[peer.peer.id] ?? false, searchQuery, isAd)
|
||||
case let .globalPeer(peer, unreadBadge, index, theme, strings, sortOrder, displayOrder, expandType, _, _, searchQuery):
|
||||
mappedItems[i] = .globalPeer(peer, unreadBadge, index, theme, strings, sortOrder, displayOrder, expandType, stats[peer.peer.id] ?? nil, requiresPremiumForMessaging[peer.peer.id] ?? false, searchQuery)
|
||||
case let .message(message, peer, combinedPeerReadState, threadInfo, presentationData, totalCount, selected, displayCustomHeader, key, resourceId, section, allPaused, _, _, searchScope):
|
||||
mappedItems[i] = .message(message, peer, combinedPeerReadState, threadInfo, presentationData, totalCount, selected, displayCustomHeader, key, resourceId, section, allPaused, stats[peer.peerId] ?? nil, requiresPremiumForMessaging[peer.peerId] ?? false, searchScope)
|
||||
default:
|
||||
@ -5263,7 +5333,7 @@ public final class ChatListSearchShimmerNode: ASDisplayNode {
|
||||
}, editPeer: { _ in
|
||||
}, openWebApp: { _ in
|
||||
}, openPhotoSetup: {
|
||||
}, openAdInfo: { _ in
|
||||
}, openAdInfo: { _, _ in
|
||||
}, openAccountFreezeInfo: {
|
||||
})
|
||||
var isInlineMode = false
|
||||
|
||||
@ -161,7 +161,7 @@ public final class ChatListShimmerNode: ASDisplayNode {
|
||||
}, editPeer: { _ in
|
||||
}, openWebApp: { _ in
|
||||
}, openPhotoSetup: {
|
||||
}, openAdInfo: { _ in
|
||||
}, openAdInfo: { _, _ in
|
||||
}, openAccountFreezeInfo: {
|
||||
})
|
||||
interaction.isInlineMode = isInlineMode
|
||||
|
||||
@ -114,7 +114,7 @@ public final class ChatListNodeInteraction {
|
||||
let editPeer: (ChatListItem) -> Void
|
||||
let openWebApp: (TelegramUser) -> Void
|
||||
let openPhotoSetup: () -> Void
|
||||
let openAdInfo: (ASDisplayNode) -> Void
|
||||
let openAdInfo: (ASDisplayNode, AdPeer) -> Void
|
||||
let openAccountFreezeInfo: () -> Void
|
||||
|
||||
public var searchTextHighightState: String?
|
||||
@ -174,7 +174,7 @@ public final class ChatListNodeInteraction {
|
||||
editPeer: @escaping (ChatListItem) -> Void,
|
||||
openWebApp: @escaping (TelegramUser) -> Void,
|
||||
openPhotoSetup: @escaping () -> Void,
|
||||
openAdInfo: @escaping (ASDisplayNode) -> Void,
|
||||
openAdInfo: @escaping (ASDisplayNode, AdPeer) -> Void,
|
||||
openAccountFreezeInfo: @escaping () -> Void
|
||||
) {
|
||||
self.activateSearch = activateSearch
|
||||
@ -1245,7 +1245,7 @@ public final class ChatListNode: ListView {
|
||||
public var openStarsTopup: ((Int64?) -> Void)?
|
||||
public var openWebApp: ((TelegramUser) -> Void)?
|
||||
public var openPhotoSetup: (() -> Void)?
|
||||
public var openAdInfo: ((ASDisplayNode) -> Void)?
|
||||
public var openAdInfo: ((ASDisplayNode, AdPeer) -> Void)?
|
||||
public var openAccountFreezeInfo: (() -> Void)?
|
||||
|
||||
private var theme: PresentationTheme
|
||||
@ -1905,8 +1905,8 @@ public final class ChatListNode: ListView {
|
||||
return
|
||||
}
|
||||
self.openPhotoSetup?()
|
||||
}, openAdInfo: { [weak self] node in
|
||||
self?.openAdInfo?(node)
|
||||
}, openAdInfo: { [weak self] node, adPeer in
|
||||
self?.openAdInfo?(node, adPeer)
|
||||
}, openAccountFreezeInfo: { [weak self] in
|
||||
self?.openAccountFreezeInfo?()
|
||||
})
|
||||
|
||||
@ -289,9 +289,8 @@ final class ChatListNoticeItemNode: ItemListRevealOptionsItemNode {
|
||||
textString = NSAttributedString(string: item.strings.ChatList_AddPhoto_Text, font: smallTextFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
|
||||
avatarPeer = accountPeer
|
||||
case .accountFreeze:
|
||||
//TODO:localize
|
||||
titleString = NSAttributedString(string: "Your account is frozen", font: titleFont, textColor: item.theme.list.itemDestructiveColor)
|
||||
textString = NSAttributedString(string: "Tap to view details and submit an appeal.", font: smallTextFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
|
||||
titleString = NSAttributedString(string: item.strings.ChatList_FrozenAccount_Title, font: titleFont, textColor: item.theme.list.itemDestructiveColor)
|
||||
textString = NSAttributedString(string: item.strings.ChatList_FrozenAccount_Text, font: smallTextFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
|
||||
}
|
||||
|
||||
var leftInset: CGFloat = sideInset
|
||||
|
||||
@ -569,14 +569,13 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
}, iconSource: nil, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
let _ = (context.engine.messages.reportAdMessage(peerId: message.id.peerId, opaqueId: adAttribute.opaqueId, option: nil)
|
||||
let _ = (context.engine.messages.reportAdMessage(opaqueId: adAttribute.opaqueId, option: nil)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
if case let .options(title, options) = result {
|
||||
if let navigationController = self?.baseNavigationController() as? NavigationController {
|
||||
navigationController.pushViewController(
|
||||
AdsReportScreen(
|
||||
context: context,
|
||||
peerId: message.id.peerId,
|
||||
opaqueId: adAttribute.opaqueId,
|
||||
title: title,
|
||||
options: options,
|
||||
|
||||
@ -3131,14 +3131,13 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
}, iconSource: nil, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
let _ = (context.engine.messages.reportAdMessage(peerId: message.id.peerId, opaqueId: adAttribute.opaqueId, option: nil)
|
||||
let _ = (context.engine.messages.reportAdMessage(opaqueId: adAttribute.opaqueId, option: nil)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
if case let .options(title, options) = result {
|
||||
if let navigationController = self?.baseNavigationController() as? NavigationController {
|
||||
navigationController.pushViewController(
|
||||
AdsReportScreen(
|
||||
context: context,
|
||||
peerId: message.id.peerId,
|
||||
opaqueId: adAttribute.opaqueId,
|
||||
title: title,
|
||||
options: options,
|
||||
|
||||
@ -36,12 +36,13 @@ public class ItemListCheckboxItem: ListViewItem, ItemListItem {
|
||||
let color: ItemListCheckboxItemColor
|
||||
let textColor: TextColor
|
||||
let checked: Bool
|
||||
let enabled: Bool
|
||||
let zeroSeparatorInsets: Bool
|
||||
public let sectionId: ItemListSectionId
|
||||
let action: () -> Void
|
||||
let deleteAction: (() -> Void)?
|
||||
|
||||
public init(presentationData: ItemListPresentationData, icon: UIImage? = nil, iconSize: CGSize? = nil, iconPlacement: IconPlacement = .default, title: String, subtitle: String? = nil, style: ItemListCheckboxItemStyle, color: ItemListCheckboxItemColor = .accent, textColor: TextColor = .primary, checked: Bool, zeroSeparatorInsets: Bool, sectionId: ItemListSectionId, action: @escaping () -> Void, deleteAction: (() -> Void)? = nil) {
|
||||
public init(presentationData: ItemListPresentationData, icon: UIImage? = nil, iconSize: CGSize? = nil, iconPlacement: IconPlacement = .default, title: String, subtitle: String? = nil, style: ItemListCheckboxItemStyle, color: ItemListCheckboxItemColor = .accent, textColor: TextColor = .primary, checked: Bool, enabled: Bool = true, zeroSeparatorInsets: Bool, sectionId: ItemListSectionId, action: @escaping () -> Void, deleteAction: (() -> Void)? = nil) {
|
||||
self.presentationData = presentationData
|
||||
self.icon = icon
|
||||
self.iconSize = iconSize
|
||||
@ -52,6 +53,7 @@ public class ItemListCheckboxItem: ListViewItem, ItemListItem {
|
||||
self.color = color
|
||||
self.textColor = textColor
|
||||
self.checked = checked
|
||||
self.enabled = enabled
|
||||
self.zeroSeparatorInsets = zeroSeparatorInsets
|
||||
self.sectionId = sectionId
|
||||
self.action = action
|
||||
@ -95,7 +97,9 @@ public class ItemListCheckboxItem: ListViewItem, ItemListItem {
|
||||
|
||||
public func selected(listView: ListView){
|
||||
listView.clearHighlightAnimated(true)
|
||||
self.action()
|
||||
if self.enabled {
|
||||
self.action()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,7 +213,7 @@ public class ItemListCheckboxItemNode: ItemListRevealOptionsItemNode {
|
||||
let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize)
|
||||
let subtitleFont = Font.regular(floor(item.presentationData.fontSize.itemListBaseFontSize * 15.0 / 17.0))
|
||||
|
||||
let titleColor: UIColor
|
||||
var titleColor: UIColor
|
||||
let subtitleColor: UIColor = item.presentationData.theme.list.itemSecondaryTextColor
|
||||
switch item.textColor {
|
||||
case .primary:
|
||||
@ -217,6 +221,9 @@ public class ItemListCheckboxItemNode: ItemListRevealOptionsItemNode {
|
||||
case .accent:
|
||||
titleColor = item.presentationData.theme.list.itemAccentColor
|
||||
}
|
||||
if !item.enabled {
|
||||
titleColor = item.presentationData.theme.list.itemDisabledTextColor
|
||||
}
|
||||
|
||||
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: titleFont, textColor: titleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 28.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
@ -239,12 +246,16 @@ public class ItemListCheckboxItemNode: ItemListRevealOptionsItemNode {
|
||||
updatedTheme = item.presentationData.theme
|
||||
}
|
||||
|
||||
if currentItem?.presentationData.theme !== item.presentationData.theme || currentItem?.color != item.color {
|
||||
switch item.color {
|
||||
case .accent:
|
||||
updateCheckImage = PresentationResourcesItemList.checkIconImage(item.presentationData.theme)
|
||||
case .secondary:
|
||||
updateCheckImage = PresentationResourcesItemList.secondaryCheckIconImage(item.presentationData.theme)
|
||||
if currentItem?.presentationData.theme !== item.presentationData.theme || currentItem?.color != item.color || currentItem?.enabled != item.enabled {
|
||||
if !item.enabled {
|
||||
updateCheckImage = PresentationResourcesItemList.disabledCheckIconImage(item.presentationData.theme)
|
||||
} else {
|
||||
switch item.color {
|
||||
case .accent:
|
||||
updateCheckImage = PresentationResourcesItemList.checkIconImage(item.presentationData.theme)
|
||||
case .secondary:
|
||||
updateCheckImage = PresentationResourcesItemList.secondaryCheckIconImage(item.presentationData.theme)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,6 +272,11 @@ public class ItemListCheckboxItemNode: ItemListRevealOptionsItemNode {
|
||||
} else {
|
||||
strongSelf.activateArea.accessibilityValue = ""
|
||||
}
|
||||
if item.enabled {
|
||||
strongSelf.activateArea.accessibilityTraits = []
|
||||
} else {
|
||||
strongSelf.activateArea.accessibilityTraits = [.notEnabled]
|
||||
}
|
||||
|
||||
strongSelf.activateArea.frame = CGRect(origin: CGPoint(x: params.leftInset, y: 0.0), size: CGSize(width: params.width - params.leftInset - params.rightInset, height: layout.contentSize.height))
|
||||
|
||||
@ -368,7 +384,7 @@ public class ItemListCheckboxItemNode: ItemListRevealOptionsItemNode {
|
||||
override public func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
|
||||
super.setHighlighted(highlighted, at: point, animated: animated)
|
||||
|
||||
if highlighted {
|
||||
if highlighted && (self.item?.enabled ?? false) {
|
||||
self.highlightedBackgroundNode.alpha = 1.0
|
||||
if self.highlightedBackgroundNode.supernode == nil {
|
||||
var anchorNode: ASDisplayNode?
|
||||
|
||||
@ -139,7 +139,7 @@ public func retry<T, E>(_ delayIncrement: Double, maxDelay: Double, onQueue queu
|
||||
}
|
||||
}
|
||||
|
||||
public func retry<T, E>(retryOnError: @escaping (E) -> Bool, delayIncrement: Double, maxDelay: Double, maxRetries: Int, onQueue queue: Queue) -> (_ signal: Signal<T, E>) -> Signal<T, E> {
|
||||
public func retry<T, E>(retryOnError: @escaping (E) -> Bool, delayIncrement: Double, maxDelay: Double, maxRetries: Int?, onQueue queue: Queue) -> (_ signal: Signal<T, E>) -> Signal<T, E> {
|
||||
return { signal in
|
||||
return Signal { subscriber in
|
||||
let shouldRetry = Atomic(value: true)
|
||||
@ -161,7 +161,7 @@ public func retry<T, E>(retryOnError: @escaping (E) -> Bool, delayIncrement: Dou
|
||||
return (min(maxDelay, value + delayIncrement), count + 1)
|
||||
}
|
||||
|
||||
if count >= maxRetries {
|
||||
if let maxRetries, count >= maxRetries {
|
||||
subscriber.putError(error)
|
||||
} else {
|
||||
let time: DispatchTime = DispatchTime.now() + Double(delay)
|
||||
|
||||
@ -141,13 +141,13 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
||||
case forwardsPreview(PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationChatBubbleCorners, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, String, Bool, String)
|
||||
case birthdayHeader(PresentationTheme, String)
|
||||
case settingHeader(PresentationTheme, String)
|
||||
case everybody(PresentationTheme, String, Bool, Bool)
|
||||
case contacts(PresentationTheme, String, Bool, Bool)
|
||||
case nobody(PresentationTheme, String, Bool, Bool)
|
||||
case everybody(PresentationTheme, String, Bool, Bool, Bool)
|
||||
case contacts(PresentationTheme, String, Bool, Bool, Bool)
|
||||
case nobody(PresentationTheme, String, Bool, Bool, Bool)
|
||||
case settingInfo(PresentationTheme, String, String)
|
||||
case exceptionsHeader(PresentationTheme, String)
|
||||
case disableFor(PresentationTheme, String, String)
|
||||
case enableFor(PresentationTheme, String, String)
|
||||
case disableFor(PresentationTheme, String, String, Bool)
|
||||
case enableFor(PresentationTheme, String, String, Bool)
|
||||
case peersInfo(PresentationTheme, String)
|
||||
case callsP2PHeader(PresentationTheme, String)
|
||||
case callsP2PAlways(PresentationTheme, String, Bool)
|
||||
@ -174,8 +174,9 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
||||
case disallowedGiftsUnlimited(PresentationTheme, String, Bool, Bool)
|
||||
case disallowedGiftsLimited(PresentationTheme, String, Bool, Bool)
|
||||
case disallowedGiftsUnique(PresentationTheme, String, Bool, Bool)
|
||||
case disallowedGiftsPremium(PresentationTheme, String, Bool, Bool)
|
||||
case disallowedGiftsInfo(PresentationTheme, String)
|
||||
case showGiftButton(PresentationTheme, String, Bool, Bool)
|
||||
case showGiftButton(PresentationTheme, String, Bool, Bool, Bool)
|
||||
case showGiftButtonInfo(PresentationTheme, String)
|
||||
|
||||
var section: ItemListSectionId {
|
||||
@ -202,7 +203,7 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
||||
return SelectivePrivacySettingsSection.hideReadTime.rawValue
|
||||
case .subscribeToPremium, .subscribeToPremiumInfo:
|
||||
return SelectivePrivacySettingsSection.premium.rawValue
|
||||
case .disallowedGiftsHeader, .disallowedGiftsUnlimited, .disallowedGiftsLimited, .disallowedGiftsUnique, .disallowedGiftsInfo:
|
||||
case .disallowedGiftsHeader, .disallowedGiftsUnlimited, .disallowedGiftsLimited, .disallowedGiftsUnique, .disallowedGiftsPremium, .disallowedGiftsInfo:
|
||||
return SelectivePrivacySettingsSection.disallowedGifts.rawValue
|
||||
case .showGiftButton, .showGiftButtonInfo:
|
||||
return SelectivePrivacySettingsSection.giftButton.rawValue
|
||||
@ -211,86 +212,88 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
||||
|
||||
var stableId: Int32 {
|
||||
switch self {
|
||||
case .forwardsPreviewHeader:
|
||||
return 0
|
||||
case .forwardsPreview:
|
||||
return 1
|
||||
case .birthdayHeader:
|
||||
return 2
|
||||
case .settingHeader:
|
||||
return 3
|
||||
case .everybody:
|
||||
return 4
|
||||
case .contacts:
|
||||
return 5
|
||||
case .nobody:
|
||||
return 6
|
||||
case .settingInfo:
|
||||
return 7
|
||||
case .phoneDiscoveryHeader:
|
||||
return 8
|
||||
case .phoneDiscoveryEverybody:
|
||||
return 9
|
||||
case .phoneDiscoveryMyContacts:
|
||||
return 10
|
||||
case .phoneDiscoveryInfo:
|
||||
return 11
|
||||
case .exceptionsHeader:
|
||||
return 12
|
||||
case .disableFor:
|
||||
return 13
|
||||
case .enableFor:
|
||||
return 14
|
||||
case .peersInfo:
|
||||
return 15
|
||||
case .callsP2PHeader:
|
||||
return 16
|
||||
case .callsP2PAlways:
|
||||
return 17
|
||||
case .callsP2PContacts:
|
||||
return 18
|
||||
case .callsP2PNever:
|
||||
return 19
|
||||
case .callsP2PInfo:
|
||||
return 20
|
||||
case .callsP2PDisableFor:
|
||||
return 21
|
||||
case .callsP2PEnableFor:
|
||||
return 22
|
||||
case .callsP2PPeersInfo:
|
||||
return 23
|
||||
case .callsIntegrationEnabled:
|
||||
return 24
|
||||
case .callsIntegrationInfo:
|
||||
return 25
|
||||
case .setPublicPhoto:
|
||||
return 26
|
||||
case .removePublicPhoto:
|
||||
return 27
|
||||
case .publicPhotoInfo:
|
||||
return 28
|
||||
case .hideReadTime:
|
||||
return 29
|
||||
case .hideReadTimeInfo:
|
||||
return 30
|
||||
case .subscribeToPremium:
|
||||
return 31
|
||||
case .subscribeToPremiumInfo:
|
||||
return 32
|
||||
case .disallowedGiftsHeader:
|
||||
return 33
|
||||
case .disallowedGiftsUnlimited:
|
||||
return 34
|
||||
case .disallowedGiftsLimited:
|
||||
return 35
|
||||
case .disallowedGiftsUnique:
|
||||
return 36
|
||||
case .disallowedGiftsInfo:
|
||||
return 37
|
||||
case .showGiftButton:
|
||||
return 38
|
||||
return 0
|
||||
case .showGiftButtonInfo:
|
||||
return 1
|
||||
case .forwardsPreviewHeader:
|
||||
return 2
|
||||
case .forwardsPreview:
|
||||
return 3
|
||||
case .birthdayHeader:
|
||||
return 4
|
||||
case .settingHeader:
|
||||
return 5
|
||||
case .everybody:
|
||||
return 6
|
||||
case .contacts:
|
||||
return 7
|
||||
case .nobody:
|
||||
return 8
|
||||
case .settingInfo:
|
||||
return 9
|
||||
case .phoneDiscoveryHeader:
|
||||
return 10
|
||||
case .phoneDiscoveryEverybody:
|
||||
return 11
|
||||
case .phoneDiscoveryMyContacts:
|
||||
return 12
|
||||
case .phoneDiscoveryInfo:
|
||||
return 13
|
||||
case .exceptionsHeader:
|
||||
return 14
|
||||
case .disableFor:
|
||||
return 15
|
||||
case .enableFor:
|
||||
return 16
|
||||
case .peersInfo:
|
||||
return 17
|
||||
case .callsP2PHeader:
|
||||
return 18
|
||||
case .callsP2PAlways:
|
||||
return 19
|
||||
case .callsP2PContacts:
|
||||
return 20
|
||||
case .callsP2PNever:
|
||||
return 21
|
||||
case .callsP2PInfo:
|
||||
return 22
|
||||
case .callsP2PDisableFor:
|
||||
return 23
|
||||
case .callsP2PEnableFor:
|
||||
return 24
|
||||
case .callsP2PPeersInfo:
|
||||
return 25
|
||||
case .callsIntegrationEnabled:
|
||||
return 26
|
||||
case .callsIntegrationInfo:
|
||||
return 27
|
||||
case .setPublicPhoto:
|
||||
return 28
|
||||
case .removePublicPhoto:
|
||||
return 29
|
||||
case .publicPhotoInfo:
|
||||
return 30
|
||||
case .hideReadTime:
|
||||
return 31
|
||||
case .hideReadTimeInfo:
|
||||
return 32
|
||||
case .subscribeToPremium:
|
||||
return 33
|
||||
case .subscribeToPremiumInfo:
|
||||
return 34
|
||||
case .disallowedGiftsHeader:
|
||||
return 35
|
||||
case .disallowedGiftsUnlimited:
|
||||
return 36
|
||||
case .disallowedGiftsLimited:
|
||||
return 37
|
||||
case .disallowedGiftsUnique:
|
||||
return 38
|
||||
case .disallowedGiftsPremium:
|
||||
return 39
|
||||
case .disallowedGiftsInfo:
|
||||
return 40
|
||||
}
|
||||
}
|
||||
|
||||
@ -320,20 +323,20 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .everybody(lhsTheme, lhsText, lhsValue, lhsIsLocked):
|
||||
if case let .everybody(rhsTheme, rhsText, rhsValue, rhsIsLocked) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsIsLocked == rhsIsLocked {
|
||||
case let .everybody(lhsTheme, lhsText, lhsValue, lhsIsLocked, lhsEnabled):
|
||||
if case let .everybody(rhsTheme, rhsText, rhsValue, rhsIsLocked, rhsEnabled) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsIsLocked == rhsIsLocked, lhsEnabled == rhsEnabled {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .contacts(lhsTheme, lhsText, lhsValue, lhsIsLocked):
|
||||
if case let .contacts(rhsTheme, rhsText, rhsValue, rhsIsLocked) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsIsLocked == rhsIsLocked {
|
||||
case let .contacts(lhsTheme, lhsText, lhsValue, lhsIsLocked, lhsEnabled):
|
||||
if case let .contacts(rhsTheme, rhsText, rhsValue, rhsIsLocked, rhsEnabled) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsIsLocked == rhsIsLocked, lhsEnabled == rhsEnabled {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .nobody(lhsTheme, lhsText, lhsValue, lhsIsLocked):
|
||||
if case let .nobody(rhsTheme, rhsText, rhsValue, rhsIsLocked) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsIsLocked == rhsIsLocked {
|
||||
case let .nobody(lhsTheme, lhsText, lhsValue, lhsIsLocked, lhsEnabled):
|
||||
if case let .nobody(rhsTheme, rhsText, rhsValue, rhsIsLocked, rhsEnabled) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsIsLocked == rhsIsLocked, lhsEnabled == rhsEnabled {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -350,14 +353,14 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .disableFor(lhsTheme, lhsText, lhsValue):
|
||||
if case let .disableFor(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||
case let .disableFor(lhsTheme, lhsText, lhsValue, lhsEnabled):
|
||||
if case let .disableFor(rhsTheme, rhsText, rhsValue, rhsEnabled) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsEnabled == rhsEnabled {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .enableFor(lhsTheme, lhsText, lhsValue):
|
||||
if case let .enableFor(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||
case let .enableFor(lhsTheme, lhsText, lhsValue, lhsEnabled):
|
||||
if case let .enableFor(rhsTheme, rhsText, rhsValue, rhsEnabled) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsEnabled == rhsEnabled {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -518,14 +521,20 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .disallowedGiftsPremium(lhsTheme, lhsText, lhsEnabled, lhsValue):
|
||||
if case let .disallowedGiftsPremium(rhsTheme, rhsText, rhsEnabled, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsEnabled == rhsEnabled, lhsValue == rhsValue {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .disallowedGiftsInfo(lhsTheme, lhsText):
|
||||
if case let .disallowedGiftsInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .showGiftButton(lhsTheme, lhsText, lhsEnabled, lhsValue):
|
||||
if case let .showGiftButton(rhsTheme, rhsText, rhsEnabled, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsEnabled == rhsEnabled, lhsValue == rhsValue {
|
||||
case let .showGiftButton(lhsTheme, lhsText, lhsEnabled, lhsValue, lhsAvailable):
|
||||
if case let .showGiftButton(rhsTheme, rhsText, rhsEnabled, rhsValue, rhsAvailable) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsEnabled == rhsEnabled, lhsValue == rhsValue, lhsAvailable == rhsAvailable {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -556,23 +565,23 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
||||
})
|
||||
case let .settingHeader(_, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, multiline: true, sectionId: self.section)
|
||||
case let .everybody(_, text, value, isLocked):
|
||||
return ItemListCheckboxItem(presentationData: presentationData, icon: !isLocked ? nil : generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/Lock"), color: presentationData.theme.list.itemSecondaryTextColor), iconPlacement: .check, title: text, style: .left, checked: value && !isLocked, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
||||
case let .everybody(_, text, value, isLocked, isEnabled):
|
||||
return ItemListCheckboxItem(presentationData: presentationData, icon: !isLocked ? nil : generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/Lock"), color: presentationData.theme.list.itemSecondaryTextColor), iconPlacement: .check, title: text, style: .left, checked: value && !isLocked, enabled: isEnabled, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
||||
if isLocked {
|
||||
} else {
|
||||
arguments.updateType(.everybody)
|
||||
}
|
||||
})
|
||||
case let .contacts(_, text, value, isLocked):
|
||||
return ItemListCheckboxItem(presentationData: presentationData, icon: !isLocked ? nil : generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/Lock"), color: presentationData.theme.list.itemSecondaryTextColor), iconPlacement: .check, title: text, style: .left, checked: value && !isLocked, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
||||
case let .contacts(_, text, value, isLocked, isEnabled):
|
||||
return ItemListCheckboxItem(presentationData: presentationData, icon: !isLocked ? nil : generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/Lock"), color: presentationData.theme.list.itemSecondaryTextColor), iconPlacement: .check, title: text, style: .left, checked: value && !isLocked, enabled: isEnabled, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
||||
if isLocked {
|
||||
arguments.displayLockedInfo()
|
||||
} else {
|
||||
arguments.updateType(.contacts)
|
||||
}
|
||||
})
|
||||
case let .nobody(_, text, value, isLocked):
|
||||
return ItemListCheckboxItem(presentationData: presentationData, icon: !isLocked ? nil : generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/Lock"), color: presentationData.theme.list.itemSecondaryTextColor), iconPlacement: .check, title: text, style: .left, checked: value && !isLocked, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
||||
case let .nobody(_, text, value, isLocked, isEnabled):
|
||||
return ItemListCheckboxItem(presentationData: presentationData, icon: !isLocked ? nil : generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/Lock"), color: presentationData.theme.list.itemSecondaryTextColor), iconPlacement: .check, title: text, style: .left, checked: value && !isLocked, enabled: isEnabled, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
||||
if isLocked {
|
||||
arguments.displayLockedInfo()
|
||||
} else {
|
||||
@ -585,12 +594,12 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
||||
})
|
||||
case let .exceptionsHeader(_, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .disableFor(_, title, value):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: title, label: value, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openSelective(.main, false)
|
||||
})
|
||||
case let .enableFor(_, title, value):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: title, label: value, sectionId: self.section, style: .blocks, action: {
|
||||
case let .disableFor(_, title, value, isEnabled):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: title, enabled: isEnabled, label: value, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openSelective(.main, false)
|
||||
})
|
||||
case let .enableFor(_, title, value, isEnabled):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: title, enabled: isEnabled, label: value, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openSelective(.main, true)
|
||||
})
|
||||
case let .peersInfo(_, text):
|
||||
@ -696,18 +705,30 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
||||
}, activatedWhileDisabled: {
|
||||
arguments.displayLockedGiftsInfo()
|
||||
})
|
||||
case let .disallowedGiftsInfo(_, text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||
case let .showGiftButton(_, text, isLocked, value):
|
||||
case let .disallowedGiftsPremium(_, text, isLocked, value):
|
||||
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, enableInteractiveChanges: !isLocked, enabled: true, displayLocked: isLocked, sectionId: self.section, style: .blocks, updated: { updatedValue in
|
||||
if !isLocked {
|
||||
arguments.updateShowGiftButton?(updatedValue)
|
||||
arguments.updateDisallowedGifts?(.premium, !updatedValue)
|
||||
} else {
|
||||
arguments.displayLockedGiftsInfo()
|
||||
}
|
||||
}, activatedWhileDisabled: {
|
||||
arguments.displayLockedGiftsInfo()
|
||||
})
|
||||
case let .disallowedGiftsInfo(_, text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||
case let .showGiftButton(_, text, isLocked, value, available):
|
||||
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, enableInteractiveChanges: !isLocked, enabled: available, displayLocked: isLocked, sectionId: self.section, style: .blocks, updated: { updatedValue in
|
||||
if !isLocked {
|
||||
arguments.updateShowGiftButton?(updatedValue)
|
||||
} else if available {
|
||||
arguments.displayLockedGiftsInfo()
|
||||
}
|
||||
}, activatedWhileDisabled: {
|
||||
if available {
|
||||
arguments.displayLockedGiftsInfo()
|
||||
}
|
||||
})
|
||||
case let .showGiftButtonInfo(_, text):
|
||||
let attributedString = NSMutableAttributedString(string: text, font: Font.regular(presentationData.fontSize.itemListBaseHeaderFontSize), textColor: presentationData.theme.list.freeTextColor)
|
||||
if let range = attributedString.string.range(of: "#") {
|
||||
@ -979,6 +1000,16 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
|
||||
enableForText = presentationData.strings.Privacy_GroupsAndChannels_AlwaysAllow
|
||||
}
|
||||
|
||||
var permisisonsEnabled = true
|
||||
if case .giftsAutoSave = kind {
|
||||
entries.append(.showGiftButton(presentationData.theme, presentationData.strings.Privacy_Gifts_ShowGiftButton, !isPremium, state.showGiftButton == true, true))
|
||||
entries.append(.showGiftButtonInfo(presentationData.theme, presentationData.strings.Privacy_Gifts_ShowGiftButtonInfo.replacingOccurrences(of: "#", with: " # ")))
|
||||
|
||||
if state.disallowedGifts == TelegramDisallowedGifts.All {
|
||||
permisisonsEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
if case .forwards = kind {
|
||||
let linkEnabled: Bool
|
||||
let tootipText: String
|
||||
@ -1004,13 +1035,13 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
|
||||
entries.append(.settingHeader(presentationData.theme, settingTitle))
|
||||
|
||||
if case .voiceMessages = kind {
|
||||
entries.append(.everybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.setting == .everybody || !isPremium, false))
|
||||
entries.append(.contacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.setting == .contacts && isPremium, !isPremium))
|
||||
entries.append(.nobody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenNobody, state.setting == .nobody && isPremium, !isPremium))
|
||||
entries.append(.everybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.setting == .everybody || !isPremium, false, permisisonsEnabled))
|
||||
entries.append(.contacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.setting == .contacts && isPremium, !isPremium, permisisonsEnabled))
|
||||
entries.append(.nobody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenNobody, state.setting == .nobody && isPremium, !isPremium, permisisonsEnabled))
|
||||
} else {
|
||||
entries.append(.everybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.setting == .everybody, false))
|
||||
entries.append(.contacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.setting == .contacts, false))
|
||||
entries.append(.nobody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenNobody, state.setting == .nobody, false))
|
||||
entries.append(.everybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.setting == .everybody, false, permisisonsEnabled))
|
||||
entries.append(.contacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.setting == .contacts, false, permisisonsEnabled))
|
||||
entries.append(.nobody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenNobody, state.setting == .nobody, false, permisisonsEnabled))
|
||||
}
|
||||
|
||||
if let settingInfoText = settingInfoText {
|
||||
@ -1033,12 +1064,12 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
|
||||
|
||||
switch state.setting {
|
||||
case .everybody:
|
||||
entries.append(.disableFor(presentationData.theme, disableForText, stringForUserCount(state.disableFor, enableForPremium: false, enableForBots: false, strings: presentationData.strings)))
|
||||
entries.append(.disableFor(presentationData.theme, disableForText, stringForUserCount(state.disableFor, enableForPremium: false, enableForBots: false, strings: presentationData.strings), permisisonsEnabled))
|
||||
case .contacts:
|
||||
entries.append(.disableFor(presentationData.theme, disableForText, stringForUserCount(state.disableFor, enableForPremium: false, enableForBots: false, strings: presentationData.strings)))
|
||||
entries.append(.enableFor(presentationData.theme, enableForText, stringForUserCount(state.enableFor, enableForPremium: state.enableForPremium, enableForBots: state.enableForBots, strings: presentationData.strings)))
|
||||
entries.append(.disableFor(presentationData.theme, disableForText, stringForUserCount(state.disableFor, enableForPremium: false, enableForBots: false, strings: presentationData.strings), permisisonsEnabled))
|
||||
entries.append(.enableFor(presentationData.theme, enableForText, stringForUserCount(state.enableFor, enableForPremium: state.enableForPremium, enableForBots: state.enableForBots, strings: presentationData.strings), permisisonsEnabled))
|
||||
case .nobody:
|
||||
entries.append(.enableFor(presentationData.theme, enableForText, stringForUserCount(state.enableFor, enableForPremium: state.enableForPremium, enableForBots: state.enableForBots, strings: presentationData.strings)))
|
||||
entries.append(.enableFor(presentationData.theme, enableForText, stringForUserCount(state.enableFor, enableForPremium: state.enableForPremium, enableForBots: state.enableForBots, strings: presentationData.strings), permisisonsEnabled))
|
||||
}
|
||||
let exceptionsInfo: String
|
||||
if case .profilePhoto = kind {
|
||||
@ -1120,14 +1151,12 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
|
||||
}
|
||||
|
||||
if case .giftsAutoSave = kind {
|
||||
//TODO:localize
|
||||
entries.append(.disallowedGiftsHeader(presentationData.theme, "ACCEPTED GIFT TYPES"))
|
||||
entries.append(.disallowedGiftsUnlimited(presentationData.theme, "Unlimited", !isPremium, !(state.disallowedGifts?.contains(.unlimited) ?? false)))
|
||||
entries.append(.disallowedGiftsLimited(presentationData.theme, "Limited-Edition", !isPremium, !(state.disallowedGifts?.contains(.limited) ?? false)))
|
||||
entries.append(.disallowedGiftsUnique(presentationData.theme, "Unique", !isPremium, !(state.disallowedGifts?.contains(.unique) ?? false)))
|
||||
entries.append(.disallowedGiftsInfo(presentationData.theme, "Choose the types of gifts that you allow others to send you."))
|
||||
entries.append(.showGiftButton(presentationData.theme, "Show Gift Icon in Chats", !isPremium, state.showGiftButton == true))
|
||||
entries.append(.showGiftButtonInfo(presentationData.theme, "Display the # Gift icon in the message input field for both participants in all chats."))
|
||||
entries.append(.disallowedGiftsHeader(presentationData.theme, presentationData.strings.Privacy_Gifts_AcceptedTypes.uppercased()))
|
||||
entries.append(.disallowedGiftsUnlimited(presentationData.theme, presentationData.strings.Privacy_Gifts_AcceptedTypes_Unlimited, !isPremium, !(state.disallowedGifts?.contains(.unlimited) ?? false)))
|
||||
entries.append(.disallowedGiftsLimited(presentationData.theme, presentationData.strings.Privacy_Gifts_AcceptedTypes_Limited, !isPremium, !(state.disallowedGifts?.contains(.limited) ?? false)))
|
||||
entries.append(.disallowedGiftsUnique(presentationData.theme, presentationData.strings.Privacy_Gifts_AcceptedTypes_Unique, !isPremium, !(state.disallowedGifts?.contains(.unique) ?? false)))
|
||||
entries.append(.disallowedGiftsPremium(presentationData.theme, presentationData.strings.Privacy_Gifts_AcceptedTypes_Premium, !isPremium, !(state.disallowedGifts?.contains(.premium) ?? false)))
|
||||
entries.append(.disallowedGiftsInfo(presentationData.theme, presentationData.strings.Privacy_Gifts_AcceptedTypes_Info))
|
||||
}
|
||||
|
||||
return entries
|
||||
@ -1603,6 +1632,12 @@ public func selectivePrivacySettingsController(
|
||||
} else {
|
||||
updatedDisallowedGifts.remove(.unique)
|
||||
}
|
||||
case .premium:
|
||||
if value {
|
||||
updatedDisallowedGifts.insert(.premium)
|
||||
} else {
|
||||
updatedDisallowedGifts.remove(.premium)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
@ -1713,7 +1748,11 @@ public func selectivePrivacySettingsController(
|
||||
disallowedGifts = value
|
||||
}
|
||||
if let value = state.showGiftButton {
|
||||
showGiftButton = value
|
||||
if disallowedGifts != TelegramDisallowedGifts.All {
|
||||
showGiftButton = value
|
||||
} else {
|
||||
showGiftButton = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -232,7 +232,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, ASScrollView
|
||||
}, editPeer: { _ in
|
||||
}, openWebApp: { _ in
|
||||
}, openPhotoSetup: {
|
||||
}, openAdInfo: { _ in
|
||||
}, openAdInfo: { _, _ in
|
||||
}, openAccountFreezeInfo: {
|
||||
})
|
||||
|
||||
|
||||
@ -381,7 +381,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
}, editPeer: { _ in
|
||||
}, openWebApp: { _ in
|
||||
}, openPhotoSetup: {
|
||||
}, openAdInfo: { _ in
|
||||
}, openAdInfo: { _, _ in
|
||||
}, openAccountFreezeInfo: {
|
||||
})
|
||||
|
||||
|
||||
@ -241,7 +241,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[2004110666] = { return Api.DialogFilterSuggested.parse_dialogFilterSuggested($0) }
|
||||
dict[-445792507] = { return Api.DialogPeer.parse_dialogPeer($0) }
|
||||
dict[1363483106] = { return Api.DialogPeer.parse_dialogPeerFolder($0) }
|
||||
dict[1653721450] = { return Api.DisallowedStarGiftsSettings.parse_disallowedStarGiftsSettings($0) }
|
||||
dict[1911715524] = { return Api.DisallowedGiftsSettings.parse_disallowedGiftsSettings($0) }
|
||||
dict[-1881881384] = { return Api.Document.parse_document($0) }
|
||||
dict[922273905] = { return Api.Document.parse_documentEmpty($0) }
|
||||
dict[297109817] = { return Api.DocumentAttribute.parse_documentAttributeAnimated($0) }
|
||||
@ -300,7 +300,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1297942941] = { return Api.GeoPoint.parse_geoPoint($0) }
|
||||
dict[286776671] = { return Api.GeoPoint.parse_geoPointEmpty($0) }
|
||||
dict[-565420653] = { return Api.GeoPointAddress.parse_geoPointAddress($0) }
|
||||
dict[-715184062] = { return Api.GlobalPrivacySettings.parse_globalPrivacySettings($0) }
|
||||
dict[-29248689] = { return Api.GlobalPrivacySettings.parse_globalPrivacySettings($0) }
|
||||
dict[-839330845] = { return Api.GroupCall.parse_groupCall($0) }
|
||||
dict[2004925620] = { return Api.GroupCall.parse_groupCallDiscarded($0) }
|
||||
dict[-341428482] = { return Api.GroupCallParticipant.parse_groupCallParticipant($0) }
|
||||
@ -1149,7 +1149,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1831650802] = { return Api.UrlAuthResult.parse_urlAuthResultRequest($0) }
|
||||
dict[34280482] = { return Api.User.parse_user($0) }
|
||||
dict[-742634630] = { return Api.User.parse_userEmpty($0) }
|
||||
dict[791719153] = { return Api.UserFull.parse_userFull($0) }
|
||||
dict[-1712881595] = { return Api.UserFull.parse_userFull($0) }
|
||||
dict[-2100168954] = { return Api.UserProfilePhoto.parse_userProfilePhoto($0) }
|
||||
dict[1326562017] = { return Api.UserProfilePhoto.parse_userProfilePhotoEmpty($0) }
|
||||
dict[164646985] = { return Api.UserStatus.parse_userStatusEmpty($0) }
|
||||
@ -1685,7 +1685,7 @@ public extension Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.DialogPeer:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.DisallowedStarGiftsSettings:
|
||||
case let _1 as Api.DisallowedGiftsSettings:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.Document:
|
||||
_1.serialize(buffer, boxed)
|
||||
|
||||
@ -614,13 +614,13 @@ public extension Api {
|
||||
}
|
||||
public extension Api {
|
||||
enum UserFull: TypeConstructorDescription {
|
||||
case userFull(flags: Int32, flags2: Int32, id: Int64, about: String?, settings: Api.PeerSettings, personalPhoto: Api.Photo?, profilePhoto: Api.Photo?, fallbackPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, botInfo: Api.BotInfo?, pinnedMsgId: Int32?, commonChatsCount: Int32, folderId: Int32?, ttlPeriod: Int32?, themeEmoticon: String?, privateForwardName: String?, botGroupAdminRights: Api.ChatAdminRights?, botBroadcastAdminRights: Api.ChatAdminRights?, wallpaper: Api.WallPaper?, stories: Api.PeerStories?, businessWorkHours: Api.BusinessWorkHours?, businessLocation: Api.BusinessLocation?, businessGreetingMessage: Api.BusinessGreetingMessage?, businessAwayMessage: Api.BusinessAwayMessage?, businessIntro: Api.BusinessIntro?, birthday: Api.Birthday?, personalChannelId: Int64?, personalChannelMessage: Int32?, stargiftsCount: Int32?, starrefProgram: Api.StarRefProgram?, botVerification: Api.BotVerification?, sendPaidMessagesStars: Int64?, disallowedStargifts: Api.DisallowedStarGiftsSettings?)
|
||||
case userFull(flags: Int32, flags2: Int32, id: Int64, about: String?, settings: Api.PeerSettings, personalPhoto: Api.Photo?, profilePhoto: Api.Photo?, fallbackPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, botInfo: Api.BotInfo?, pinnedMsgId: Int32?, commonChatsCount: Int32, folderId: Int32?, ttlPeriod: Int32?, themeEmoticon: String?, privateForwardName: String?, botGroupAdminRights: Api.ChatAdminRights?, botBroadcastAdminRights: Api.ChatAdminRights?, wallpaper: Api.WallPaper?, stories: Api.PeerStories?, businessWorkHours: Api.BusinessWorkHours?, businessLocation: Api.BusinessLocation?, businessGreetingMessage: Api.BusinessGreetingMessage?, businessAwayMessage: Api.BusinessAwayMessage?, businessIntro: Api.BusinessIntro?, birthday: Api.Birthday?, personalChannelId: Int64?, personalChannelMessage: Int32?, stargiftsCount: Int32?, starrefProgram: Api.StarRefProgram?, botVerification: Api.BotVerification?, sendPaidMessagesStars: Int64?, disallowedGifts: Api.DisallowedGiftsSettings?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .userFull(let flags, let flags2, let id, let about, let settings, let personalPhoto, let profilePhoto, let fallbackPhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId, let ttlPeriod, let themeEmoticon, let privateForwardName, let botGroupAdminRights, let botBroadcastAdminRights, let wallpaper, let stories, let businessWorkHours, let businessLocation, let businessGreetingMessage, let businessAwayMessage, let businessIntro, let birthday, let personalChannelId, let personalChannelMessage, let stargiftsCount, let starrefProgram, let botVerification, let sendPaidMessagesStars, let disallowedStargifts):
|
||||
case .userFull(let flags, let flags2, let id, let about, let settings, let personalPhoto, let profilePhoto, let fallbackPhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId, let ttlPeriod, let themeEmoticon, let privateForwardName, let botGroupAdminRights, let botBroadcastAdminRights, let wallpaper, let stories, let businessWorkHours, let businessLocation, let businessGreetingMessage, let businessAwayMessage, let businessIntro, let birthday, let personalChannelId, let personalChannelMessage, let stargiftsCount, let starrefProgram, let botVerification, let sendPaidMessagesStars, let disallowedGifts):
|
||||
if boxed {
|
||||
buffer.appendInt32(791719153)
|
||||
buffer.appendInt32(-1712881595)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt32(flags2, buffer: buffer, boxed: false)
|
||||
@ -654,15 +654,15 @@ public extension Api {
|
||||
if Int(flags2) & Int(1 << 11) != 0 {starrefProgram!.serialize(buffer, true)}
|
||||
if Int(flags2) & Int(1 << 12) != 0 {botVerification!.serialize(buffer, true)}
|
||||
if Int(flags2) & Int(1 << 14) != 0 {serializeInt64(sendPaidMessagesStars!, buffer: buffer, boxed: false)}
|
||||
if Int(flags2) & Int(1 << 15) != 0 {disallowedStargifts!.serialize(buffer, true)}
|
||||
if Int(flags2) & Int(1 << 15) != 0 {disallowedGifts!.serialize(buffer, true)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .userFull(let flags, let flags2, let id, let about, let settings, let personalPhoto, let profilePhoto, let fallbackPhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId, let ttlPeriod, let themeEmoticon, let privateForwardName, let botGroupAdminRights, let botBroadcastAdminRights, let wallpaper, let stories, let businessWorkHours, let businessLocation, let businessGreetingMessage, let businessAwayMessage, let businessIntro, let birthday, let personalChannelId, let personalChannelMessage, let stargiftsCount, let starrefProgram, let botVerification, let sendPaidMessagesStars, let disallowedStargifts):
|
||||
return ("userFull", [("flags", flags as Any), ("flags2", flags2 as Any), ("id", id as Any), ("about", about as Any), ("settings", settings as Any), ("personalPhoto", personalPhoto as Any), ("profilePhoto", profilePhoto as Any), ("fallbackPhoto", fallbackPhoto as Any), ("notifySettings", notifySettings as Any), ("botInfo", botInfo as Any), ("pinnedMsgId", pinnedMsgId as Any), ("commonChatsCount", commonChatsCount as Any), ("folderId", folderId as Any), ("ttlPeriod", ttlPeriod as Any), ("themeEmoticon", themeEmoticon as Any), ("privateForwardName", privateForwardName as Any), ("botGroupAdminRights", botGroupAdminRights as Any), ("botBroadcastAdminRights", botBroadcastAdminRights as Any), ("wallpaper", wallpaper as Any), ("stories", stories as Any), ("businessWorkHours", businessWorkHours as Any), ("businessLocation", businessLocation as Any), ("businessGreetingMessage", businessGreetingMessage as Any), ("businessAwayMessage", businessAwayMessage as Any), ("businessIntro", businessIntro as Any), ("birthday", birthday as Any), ("personalChannelId", personalChannelId as Any), ("personalChannelMessage", personalChannelMessage as Any), ("stargiftsCount", stargiftsCount as Any), ("starrefProgram", starrefProgram as Any), ("botVerification", botVerification as Any), ("sendPaidMessagesStars", sendPaidMessagesStars as Any), ("disallowedStargifts", disallowedStargifts as Any)])
|
||||
case .userFull(let flags, let flags2, let id, let about, let settings, let personalPhoto, let profilePhoto, let fallbackPhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId, let ttlPeriod, let themeEmoticon, let privateForwardName, let botGroupAdminRights, let botBroadcastAdminRights, let wallpaper, let stories, let businessWorkHours, let businessLocation, let businessGreetingMessage, let businessAwayMessage, let businessIntro, let birthday, let personalChannelId, let personalChannelMessage, let stargiftsCount, let starrefProgram, let botVerification, let sendPaidMessagesStars, let disallowedGifts):
|
||||
return ("userFull", [("flags", flags as Any), ("flags2", flags2 as Any), ("id", id as Any), ("about", about as Any), ("settings", settings as Any), ("personalPhoto", personalPhoto as Any), ("profilePhoto", profilePhoto as Any), ("fallbackPhoto", fallbackPhoto as Any), ("notifySettings", notifySettings as Any), ("botInfo", botInfo as Any), ("pinnedMsgId", pinnedMsgId as Any), ("commonChatsCount", commonChatsCount as Any), ("folderId", folderId as Any), ("ttlPeriod", ttlPeriod as Any), ("themeEmoticon", themeEmoticon as Any), ("privateForwardName", privateForwardName as Any), ("botGroupAdminRights", botGroupAdminRights as Any), ("botBroadcastAdminRights", botBroadcastAdminRights as Any), ("wallpaper", wallpaper as Any), ("stories", stories as Any), ("businessWorkHours", businessWorkHours as Any), ("businessLocation", businessLocation as Any), ("businessGreetingMessage", businessGreetingMessage as Any), ("businessAwayMessage", businessAwayMessage as Any), ("businessIntro", businessIntro as Any), ("birthday", birthday as Any), ("personalChannelId", personalChannelId as Any), ("personalChannelMessage", personalChannelMessage as Any), ("stargiftsCount", stargiftsCount as Any), ("starrefProgram", starrefProgram as Any), ("botVerification", botVerification as Any), ("sendPaidMessagesStars", sendPaidMessagesStars as Any), ("disallowedGifts", disallowedGifts as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -767,9 +767,9 @@ public extension Api {
|
||||
} }
|
||||
var _32: Int64?
|
||||
if Int(_2!) & Int(1 << 14) != 0 {_32 = reader.readInt64() }
|
||||
var _33: Api.DisallowedStarGiftsSettings?
|
||||
var _33: Api.DisallowedGiftsSettings?
|
||||
if Int(_2!) & Int(1 << 15) != 0 {if let signature = reader.readInt32() {
|
||||
_33 = Api.parse(reader, signature: signature) as? Api.DisallowedStarGiftsSettings
|
||||
_33 = Api.parse(reader, signature: signature) as? Api.DisallowedGiftsSettings
|
||||
} }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
@ -805,7 +805,7 @@ public extension Api {
|
||||
let _c32 = (Int(_2!) & Int(1 << 14) == 0) || _32 != nil
|
||||
let _c33 = (Int(_2!) & Int(1 << 15) == 0) || _33 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 && _c27 && _c28 && _c29 && _c30 && _c31 && _c32 && _c33 {
|
||||
return Api.UserFull.userFull(flags: _1!, flags2: _2!, id: _3!, about: _4, settings: _5!, personalPhoto: _6, profilePhoto: _7, fallbackPhoto: _8, notifySettings: _9!, botInfo: _10, pinnedMsgId: _11, commonChatsCount: _12!, folderId: _13, ttlPeriod: _14, themeEmoticon: _15, privateForwardName: _16, botGroupAdminRights: _17, botBroadcastAdminRights: _18, wallpaper: _19, stories: _20, businessWorkHours: _21, businessLocation: _22, businessGreetingMessage: _23, businessAwayMessage: _24, businessIntro: _25, birthday: _26, personalChannelId: _27, personalChannelMessage: _28, stargiftsCount: _29, starrefProgram: _30, botVerification: _31, sendPaidMessagesStars: _32, disallowedStargifts: _33)
|
||||
return Api.UserFull.userFull(flags: _1!, flags2: _2!, id: _3!, about: _4, settings: _5!, personalPhoto: _6, profilePhoto: _7, fallbackPhoto: _8, notifySettings: _9!, botInfo: _10, pinnedMsgId: _11, commonChatsCount: _12!, folderId: _13, ttlPeriod: _14, themeEmoticon: _15, privateForwardName: _16, botGroupAdminRights: _17, botBroadcastAdminRights: _18, wallpaper: _19, stories: _20, businessWorkHours: _21, businessLocation: _22, businessGreetingMessage: _23, businessAwayMessage: _24, businessIntro: _25, birthday: _26, personalChannelId: _27, personalChannelMessage: _28, stargiftsCount: _29, starrefProgram: _30, botVerification: _31, sendPaidMessagesStars: _32, disallowedGifts: _33)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
||||
@ -1425,14 +1425,14 @@ public extension Api {
|
||||
}
|
||||
}
|
||||
public extension Api {
|
||||
enum DisallowedStarGiftsSettings: TypeConstructorDescription {
|
||||
case disallowedStarGiftsSettings(flags: Int32)
|
||||
enum DisallowedGiftsSettings: TypeConstructorDescription {
|
||||
case disallowedGiftsSettings(flags: Int32)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .disallowedStarGiftsSettings(let flags):
|
||||
case .disallowedGiftsSettings(let flags):
|
||||
if boxed {
|
||||
buffer.appendInt32(1653721450)
|
||||
buffer.appendInt32(1911715524)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
break
|
||||
@ -1441,17 +1441,17 @@ public extension Api {
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .disallowedStarGiftsSettings(let flags):
|
||||
return ("disallowedStarGiftsSettings", [("flags", flags as Any)])
|
||||
case .disallowedGiftsSettings(let flags):
|
||||
return ("disallowedGiftsSettings", [("flags", flags as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_disallowedStarGiftsSettings(_ reader: BufferReader) -> DisallowedStarGiftsSettings? {
|
||||
public static func parse_disallowedGiftsSettings(_ reader: BufferReader) -> DisallowedGiftsSettings? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.DisallowedStarGiftsSettings.disallowedStarGiftsSettings(flags: _1!)
|
||||
return Api.DisallowedGiftsSettings.disallowedGiftsSettings(flags: _1!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
||||
@ -946,25 +946,25 @@ public extension Api {
|
||||
}
|
||||
public extension Api {
|
||||
enum GlobalPrivacySettings: TypeConstructorDescription {
|
||||
case globalPrivacySettings(flags: Int32, noncontactPeersPaidStars: Int64?, disallowedStargifts: Api.DisallowedStarGiftsSettings?)
|
||||
case globalPrivacySettings(flags: Int32, noncontactPeersPaidStars: Int64?, disallowedGifts: Api.DisallowedGiftsSettings?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .globalPrivacySettings(let flags, let noncontactPeersPaidStars, let disallowedStargifts):
|
||||
case .globalPrivacySettings(let flags, let noncontactPeersPaidStars, let disallowedGifts):
|
||||
if boxed {
|
||||
buffer.appendInt32(-715184062)
|
||||
buffer.appendInt32(-29248689)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 5) != 0 {serializeInt64(noncontactPeersPaidStars!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 6) != 0 {disallowedStargifts!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 6) != 0 {disallowedGifts!.serialize(buffer, true)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .globalPrivacySettings(let flags, let noncontactPeersPaidStars, let disallowedStargifts):
|
||||
return ("globalPrivacySettings", [("flags", flags as Any), ("noncontactPeersPaidStars", noncontactPeersPaidStars as Any), ("disallowedStargifts", disallowedStargifts as Any)])
|
||||
case .globalPrivacySettings(let flags, let noncontactPeersPaidStars, let disallowedGifts):
|
||||
return ("globalPrivacySettings", [("flags", flags as Any), ("noncontactPeersPaidStars", noncontactPeersPaidStars as Any), ("disallowedGifts", disallowedGifts as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -973,15 +973,15 @@ public extension Api {
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int64?
|
||||
if Int(_1!) & Int(1 << 5) != 0 {_2 = reader.readInt64() }
|
||||
var _3: Api.DisallowedStarGiftsSettings?
|
||||
var _3: Api.DisallowedGiftsSettings?
|
||||
if Int(_1!) & Int(1 << 6) != 0 {if let signature = reader.readInt32() {
|
||||
_3 = Api.parse(reader, signature: signature) as? Api.DisallowedStarGiftsSettings
|
||||
_3 = Api.parse(reader, signature: signature) as? Api.DisallowedGiftsSettings
|
||||
} }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = (Int(_1!) & Int(1 << 5) == 0) || _2 != nil
|
||||
let _c3 = (Int(_1!) & Int(1 << 6) == 0) || _3 != nil
|
||||
if _c1 && _c2 && _c3 {
|
||||
return Api.GlobalPrivacySettings.globalPrivacySettings(flags: _1!, noncontactPeersPaidStars: _2, disallowedStargifts: _3)
|
||||
return Api.GlobalPrivacySettings.globalPrivacySettings(flags: _1!, noncontactPeersPaidStars: _2, disallowedGifts: _3)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
||||
@ -1224,6 +1224,20 @@ public func retryRequest<T>(signal: Signal<T, MTRpcError>) -> Signal<T, NoError>
|
||||
|> retry(0.2, maxDelay: 5.0, onQueue: Queue.concurrentDefaultQueue())
|
||||
}
|
||||
|
||||
public func retryRequestIfNotFrozen<T>(signal: Signal<T, MTRpcError>) -> Signal<T?, NoError> {
|
||||
return signal
|
||||
|> retry(retryOnError: { error in
|
||||
if error.errorDescription == "FROZEN_METHOD_INVALID" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}, delayIncrement: 0.2, maxDelay: 5.0, maxRetries: nil, onQueue: .concurrentDefaultQueue())
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ in
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
|
||||
class Keychain: NSObject, MTKeychain {
|
||||
let get: (String) -> Data?
|
||||
let set: (String, Data) -> Void
|
||||
|
||||
@ -306,6 +306,14 @@ public struct TelegramDisallowedGifts: OptionSet, Codable {
|
||||
public static let unlimited = TelegramDisallowedGifts(rawValue: 1 << 0)
|
||||
public static let limited = TelegramDisallowedGifts(rawValue: 1 << 1)
|
||||
public static let unique = TelegramDisallowedGifts(rawValue: 1 << 2)
|
||||
public static let premium = TelegramDisallowedGifts(rawValue: 1 << 3)
|
||||
|
||||
public static let All: TelegramDisallowedGifts = [
|
||||
.unlimited,
|
||||
.limited,
|
||||
.unique,
|
||||
.premium
|
||||
]
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
@ -241,8 +241,7 @@ func fetchChatList(accountPeerId: PeerId, postbox: Postbox, network: Network, lo
|
||||
folderId = groupId.rawValue
|
||||
}
|
||||
additionalPinnedChats = network.request(Api.functions.messages.getPinnedDialogs(folderId: folderId))
|
||||
|> retryRequest
|
||||
|> map(Optional.init)
|
||||
|> retryRequestIfNotFrozen
|
||||
} else {
|
||||
additionalPinnedChats = .single(nil)
|
||||
}
|
||||
|
||||
@ -8,8 +8,11 @@ import MtProtoKit
|
||||
func managedAutodownloadSettingsUpdates(accountManager: AccountManager<TelegramAccountManagerTypes>, network: Network) -> Signal<Void, NoError> {
|
||||
let poll = Signal<Void, NoError> { subscriber in
|
||||
return (network.request(Api.functions.account.getAutoDownloadSettings())
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<Void, NoError> in
|
||||
guard let result else {
|
||||
return .complete()
|
||||
}
|
||||
return updateAutodownloadSettingsInteractively(accountManager: accountManager, { _ -> AutodownloadSettings in
|
||||
return AutodownloadSettings(apiAutodownloadSettings: result)
|
||||
})
|
||||
|
||||
@ -9,7 +9,7 @@ func managedConfigurationUpdates(accountManager: AccountManager<TelegramAccountM
|
||||
let poll = Signal<Void, NoError> { subscriber in
|
||||
return (combineLatest(
|
||||
network.request(Api.functions.help.getConfig()) |> retryRequest,
|
||||
network.request(Api.functions.messages.getDefaultHistoryTTL()) |> retryRequest
|
||||
network.request(Api.functions.messages.getDefaultHistoryTTL()) |> retryRequestIfNotFrozen
|
||||
)
|
||||
|> mapToSignal { result, defaultHistoryTtl -> Signal<Void, NoError> in
|
||||
return postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
@ -83,6 +83,8 @@ func managedConfigurationUpdates(accountManager: AccountManager<TelegramAccountM
|
||||
} else {
|
||||
messageAutoremoveSeconds = nil
|
||||
}
|
||||
default:
|
||||
messageAutoremoveSeconds = nil
|
||||
}
|
||||
updateGlobalMessageAutoremoveTimeoutSettings(transaction: transaction, { settings in
|
||||
var settings = settings
|
||||
|
||||
@ -21,7 +21,7 @@ public func updateGlobalNotificationSettingsInteractively(postbox: Postbox, _ f:
|
||||
|
||||
public func resetPeerNotificationSettings(network: Network) -> Signal<Void, NoError> {
|
||||
return network.request(Api.functions.account.resetNotifySettings())
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { _ in return Signal<Void, NoError>.complete() }
|
||||
}
|
||||
|
||||
@ -113,8 +113,11 @@ private func fetchedNotificationSettings(network: Network) -> Signal<GlobalNotif
|
||||
let reactions = network.request(Api.functions.account.getReactionsNotifySettings())
|
||||
|
||||
return combineLatest(chats, users, channels, contactsJoinedMuted, reactions)
|
||||
|> retryRequest
|
||||
|> map { chats, users, channels, contactsJoinedMuted, reactions in
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { data in
|
||||
guard let (chats, users, channels, contactsJoinedMuted, reactions) = data else {
|
||||
return .complete()
|
||||
}
|
||||
let chatsSettings: MessageNotificationSettings
|
||||
switch chats {
|
||||
case let .peerNotifySettings(_, showPreviews, _, muteUntil, iosSound, _, desktopSound, storiesMuted, storiesHideSender, storiesIosSound, _, storiesDesktopSound):
|
||||
@ -306,7 +309,7 @@ private func fetchedNotificationSettings(network: Network) -> Signal<GlobalNotif
|
||||
)
|
||||
}
|
||||
|
||||
return GlobalNotificationSettingsSet(privateChats: userSettings, groupChats: chatsSettings, channels: channelSettings, reactionSettings: reactionSettings, contactsJoined: contactsJoinedMuted == .boolFalse)
|
||||
return .single(GlobalNotificationSettingsSet(privateChats: userSettings, groupChats: chatsSettings, channels: channelSettings, reactionSettings: reactionSettings, contactsJoined: contactsJoinedMuted == .boolFalse))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -45,8 +45,11 @@ private func managedRecentMedia(postbox: Postbox, network: Network, collectionId
|
||||
func managedRecentStickers(postbox: Postbox, network: Network, forceFetch: Bool = false) -> Signal<Void, NoError> {
|
||||
return managedRecentMedia(postbox: postbox, network: network, collectionId: Namespaces.OrderedItemList.CloudRecentStickers, extractItemId: { RecentMediaItemId($0).mediaId.id }, reverseHashOrder: false, forceFetch: forceFetch, fetch: { hash in
|
||||
return network.request(Api.functions.messages.getRecentStickers(flags: 0, hash: hash))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
switch result {
|
||||
case .recentStickersNotModified:
|
||||
return .single(nil)
|
||||
@ -68,8 +71,11 @@ func managedRecentStickers(postbox: Postbox, network: Network, forceFetch: Bool
|
||||
func managedRecentGifs(postbox: Postbox, network: Network, forceFetch: Bool = false) -> Signal<Void, NoError> {
|
||||
return managedRecentMedia(postbox: postbox, network: network, collectionId: Namespaces.OrderedItemList.CloudRecentGifs, extractItemId: { RecentMediaItemId($0).mediaId.id }, reverseHashOrder: false, forceFetch: forceFetch, fetch: { hash in
|
||||
return network.request(Api.functions.messages.getSavedGifs(hash: hash))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
switch result {
|
||||
case .savedGifsNotModified:
|
||||
return .single(nil)
|
||||
@ -91,8 +97,11 @@ func managedRecentGifs(postbox: Postbox, network: Network, forceFetch: Bool = fa
|
||||
func managedSavedStickers(postbox: Postbox, network: Network, forceFetch: Bool = false) -> Signal<Void, NoError> {
|
||||
return managedRecentMedia(postbox: postbox, network: network, collectionId: Namespaces.OrderedItemList.CloudSavedStickers, extractItemId: { RecentMediaItemId($0).mediaId.id }, reverseHashOrder: true, forceFetch: forceFetch, fetch: { hash in
|
||||
return network.request(Api.functions.messages.getFavedStickers(hash: hash))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
switch result {
|
||||
case .favedStickersNotModified:
|
||||
return .single(nil)
|
||||
@ -133,8 +142,11 @@ func managedSavedStickers(postbox: Postbox, network: Network, forceFetch: Bool =
|
||||
func managedGreetingStickers(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
||||
let poll = managedRecentMedia(postbox: postbox, network: network, collectionId: Namespaces.OrderedItemList.CloudGreetingStickers, extractItemId: { RecentMediaItemId($0).mediaId.id }, reverseHashOrder: false, forceFetch: false, fetch: { hash in
|
||||
return network.request(Api.functions.messages.getStickers(emoticon: "👋⭐️", hash: 0))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
switch result {
|
||||
case .stickersNotModified:
|
||||
return .single(nil)
|
||||
@ -157,8 +169,11 @@ func managedGreetingStickers(postbox: Postbox, network: Network) -> Signal<Void,
|
||||
func managedPremiumStickers(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
||||
let poll = managedRecentMedia(postbox: postbox, network: network, collectionId: Namespaces.OrderedItemList.CloudPremiumStickers, extractItemId: { RecentMediaItemId($0).mediaId.id }, reverseHashOrder: false, forceFetch: false, fetch: { hash in
|
||||
return network.request(Api.functions.messages.getStickers(emoticon: "⭐️⭐️", hash: 0))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
switch result {
|
||||
case .stickersNotModified:
|
||||
return .single(nil)
|
||||
@ -181,8 +196,11 @@ func managedPremiumStickers(postbox: Postbox, network: Network) -> Signal<Void,
|
||||
func managedAllPremiumStickers(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
||||
let poll = managedRecentMedia(postbox: postbox, network: network, collectionId: Namespaces.OrderedItemList.CloudAllPremiumStickers, extractItemId: { RecentMediaItemId($0).mediaId.id }, reverseHashOrder: false, forceFetch: false, fetch: { hash in
|
||||
return network.request(Api.functions.messages.getStickers(emoticon: "📂⭐️", hash: 0))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
switch result {
|
||||
case .stickersNotModified:
|
||||
return .single(nil)
|
||||
@ -205,8 +223,11 @@ func managedAllPremiumStickers(postbox: Postbox, network: Network) -> Signal<Voi
|
||||
func managedRecentStatusEmoji(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
||||
let poll = managedRecentMedia(postbox: postbox, network: network, collectionId: Namespaces.OrderedItemList.CloudRecentStatusEmoji, extractItemId: { RecentMediaItemId($0).mediaId.id }, reverseHashOrder: false, forceFetch: false, fetch: { hash in
|
||||
return network.request(Api.functions.account.getRecentEmojiStatuses(hash: hash))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
switch result {
|
||||
case .emojiStatusesNotModified:
|
||||
return .single(nil)
|
||||
@ -235,8 +256,11 @@ func managedRecentStatusEmoji(postbox: Postbox, network: Network) -> Signal<Void
|
||||
func managedFeaturedStatusEmoji(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
||||
let poll = managedRecentMedia(postbox: postbox, network: network, collectionId: Namespaces.OrderedItemList.CloudFeaturedStatusEmoji, extractItemId: { RecentMediaItemId($0).mediaId.id }, reverseHashOrder: false, forceFetch: false, fetch: { hash in
|
||||
return network.request(Api.functions.account.getDefaultEmojiStatuses(hash: hash))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
switch result {
|
||||
case .emojiStatusesNotModified:
|
||||
return .single(nil)
|
||||
@ -265,8 +289,11 @@ func managedFeaturedStatusEmoji(postbox: Postbox, network: Network) -> Signal<Vo
|
||||
func managedFeaturedChannelStatusEmoji(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
||||
let poll = managedRecentMedia(postbox: postbox, network: network, collectionId: Namespaces.OrderedItemList.CloudFeaturedChannelStatusEmoji, extractItemId: { RecentMediaItemId($0).mediaId.id }, reverseHashOrder: false, forceFetch: false, fetch: { hash in
|
||||
return network.request(Api.functions.account.getChannelDefaultEmojiStatuses(hash: hash))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
switch result {
|
||||
case .emojiStatusesNotModified:
|
||||
return .single(nil)
|
||||
@ -295,8 +322,11 @@ func managedFeaturedChannelStatusEmoji(postbox: Postbox, network: Network) -> Si
|
||||
func managedUniqueStarGifts(accountPeerId: PeerId, postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
||||
let poll = managedRecentMedia(postbox: postbox, network: network, collectionId: Namespaces.OrderedItemList.CloudUniqueStarGifts, extractItemId: { RecentStarGiftItemId($0).id }, reverseHashOrder: false, forceFetch: false, fetch: { hash in
|
||||
return network.request(Api.functions.account.getCollectibleEmojiStatuses(hash: hash))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
switch result {
|
||||
case .emojiStatusesNotModified:
|
||||
return .single(nil)
|
||||
@ -345,8 +375,11 @@ func managedUniqueStarGifts(accountPeerId: PeerId, postbox: Postbox, network: Ne
|
||||
func managedProfilePhotoEmoji(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
||||
let poll = managedRecentMedia(postbox: postbox, network: network, collectionId: Namespaces.OrderedItemList.CloudFeaturedProfilePhotoEmoji, extractItemId: { RecentMediaItemId($0).mediaId.id }, reverseHashOrder: false, forceFetch: false, fetch: { hash in
|
||||
return network.request(Api.functions.account.getDefaultProfilePhotoEmojis(hash: hash))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
switch result {
|
||||
case .emojiListNotModified:
|
||||
return .single(nil)
|
||||
@ -373,8 +406,11 @@ func managedProfilePhotoEmoji(postbox: Postbox, network: Network) -> Signal<Void
|
||||
func managedGroupPhotoEmoji(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
||||
let poll = managedRecentMedia(postbox: postbox, network: network, collectionId: Namespaces.OrderedItemList.CloudFeaturedGroupPhotoEmoji, extractItemId: { RecentMediaItemId($0).mediaId.id }, reverseHashOrder: false, forceFetch: false, fetch: { hash in
|
||||
return network.request(Api.functions.account.getDefaultGroupPhotoEmojis(hash: hash))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
switch result {
|
||||
case .emojiListNotModified:
|
||||
return .single(nil)
|
||||
@ -401,8 +437,11 @@ func managedGroupPhotoEmoji(postbox: Postbox, network: Network) -> Signal<Void,
|
||||
func managedBackgroundIconEmoji(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
||||
let poll = managedRecentMedia(postbox: postbox, network: network, collectionId: Namespaces.OrderedItemList.CloudFeaturedBackgroundIconEmoji, extractItemId: { RecentMediaItemId($0).mediaId.id }, reverseHashOrder: false, forceFetch: false, fetch: { hash in
|
||||
return network.request(Api.functions.account.getDefaultBackgroundEmojis(hash: hash))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
switch result {
|
||||
case .emojiListNotModified:
|
||||
return .single(nil)
|
||||
@ -429,8 +468,11 @@ func managedBackgroundIconEmoji(postbox: Postbox, network: Network) -> Signal<Vo
|
||||
func managedDisabledChannelStatusIconEmoji(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
||||
let poll = managedRecentMedia(postbox: postbox, network: network, collectionId: Namespaces.OrderedItemList.CloudDisabledChannelStatusEmoji, extractItemId: { RecentMediaItemId($0).mediaId.id }, reverseHashOrder: false, forceFetch: false, fetch: { hash in
|
||||
return network.request(Api.functions.account.getChannelRestrictedStatusEmojis(hash: hash))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
switch result {
|
||||
case .emojiListNotModified:
|
||||
return .single(nil)
|
||||
@ -466,8 +508,11 @@ func managedRecentReactions(postbox: Postbox, network: Network) -> Signal<Void,
|
||||
}
|
||||
}, reverseHashOrder: false, forceFetch: false, fetch: { hash in
|
||||
return network.request(Api.functions.messages.getRecentReactions(limit: 100, hash: hash))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
switch result {
|
||||
case .reactionsNotModified:
|
||||
return .single(nil)
|
||||
@ -523,8 +568,11 @@ func managedTopReactions(postbox: Postbox, network: Network) -> Signal<Void, NoE
|
||||
}
|
||||
}, reverseHashOrder: false, forceFetch: false, fetch: { hash in
|
||||
return network.request(Api.functions.messages.getTopReactions(limit: 32, hash: hash))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
switch result {
|
||||
case .reactionsNotModified:
|
||||
return .single(nil)
|
||||
@ -580,8 +628,11 @@ func managedDefaultTagReactions(postbox: Postbox, network: Network) -> Signal<Vo
|
||||
}
|
||||
}, reverseHashOrder: false, forceFetch: false, fetch: { hash in
|
||||
return network.request(Api.functions.messages.getDefaultTagReactions(hash: hash))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[OrderedItemListEntry]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
switch result {
|
||||
case .reactionsNotModified:
|
||||
return .single(nil)
|
||||
|
||||
@ -139,6 +139,7 @@ private func hashForStickerPackInfos(_ infos: [StickerPackCollectionInfo]) -> In
|
||||
private enum SynchronizeInstalledStickerPacksError {
|
||||
case restart
|
||||
case done
|
||||
case frozen
|
||||
}
|
||||
|
||||
private func fetchStickerPack(network: Network, info: StickerPackCollectionInfo) -> Signal<(StickerPackCollectionInfo, [ItemCollectionItem]), NoError> {
|
||||
@ -479,10 +480,13 @@ private func continueSynchronizeInstalledStickerPacks(transaction: Transaction,
|
||||
}
|
||||
|
||||
let sequence = request
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapError { _ -> SynchronizeInstalledStickerPacksError in
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, SynchronizeInstalledStickerPacksError> in
|
||||
guard let result else {
|
||||
return .fail(.frozen)
|
||||
}
|
||||
return postbox.transaction { transaction -> Signal<Void, SynchronizeInstalledStickerPacksError> in
|
||||
let checkLocalCollectionInfos = transaction.getItemCollectionsInfos(namespace: collectionNamespace).map { $0.1 as! StickerPackCollectionInfo }
|
||||
if checkLocalCollectionInfos != localCollectionInfos {
|
||||
@ -714,6 +718,8 @@ private func continueSynchronizeInstalledStickerPacks(transaction: Transaction,
|
||||
return ((sequence
|
||||
|> `catch` { error -> Signal<Void, SynchronizeInstalledStickerPacksError> in
|
||||
switch error {
|
||||
case .frozen:
|
||||
return .fail(.frozen)
|
||||
case .done:
|
||||
return .fail(.done)
|
||||
case .restart:
|
||||
|
||||
@ -129,8 +129,11 @@ private func synchronizePinnedChats(transaction: Transaction, postbox: Postbox,
|
||||
}
|
||||
|
||||
return network.request(Api.functions.messages.getPinnedDialogs(folderId: groupId.rawValue))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { dialogs -> Signal<Void, NoError> in
|
||||
guard let dialogs else {
|
||||
return .complete()
|
||||
}
|
||||
return postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
var storeMessages: [StoreMessage] = []
|
||||
var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:]
|
||||
|
||||
@ -172,10 +172,14 @@ private func requestStarsRevenueStats(postbox: Postbox, network: Network, peerId
|
||||
}
|
||||
|
||||
return network.request(Api.functions.payments.getStarsRevenueStats(flags: flags, peer: inputPeer))
|
||||
|> retryRequestIfNotFrozen
|
||||
|> map { result -> StarsRevenueStats? in
|
||||
guard let result else {
|
||||
return nil
|
||||
}
|
||||
return StarsRevenueStats(apiStarsRevenueStats: result, peerId: peerId)
|
||||
}
|
||||
|> retryRequest
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1000,7 +1000,7 @@ public final class CachedUserData: CachedPeerData {
|
||||
public let starRefProgram: TelegramStarRefProgram?
|
||||
public let verification: PeerVerification?
|
||||
public let sendPaidMessageStars: StarsAmount?
|
||||
public let disallowedGifts: TelegramDisallowedGifts
|
||||
public let disallowedGifts: TelegramDisallowedGifts?
|
||||
|
||||
public let peerIds: Set<PeerId>
|
||||
public let messageIds: Set<MessageId>
|
||||
@ -1042,10 +1042,10 @@ public final class CachedUserData: CachedPeerData {
|
||||
self.starRefProgram = nil
|
||||
self.verification = nil
|
||||
self.sendPaidMessageStars = nil
|
||||
self.disallowedGifts = []
|
||||
self.disallowedGifts = nil
|
||||
}
|
||||
|
||||
public init(about: String?, botInfo: BotInfo?, editableBotInfo: EditableBotInfo?, peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, isBlocked: Bool, commonGroupCount: Int32, voiceCallsAvailable: Bool, videoCallsAvailable: Bool, callsPrivate: Bool, canPinMessages: Bool, hasScheduledMessages: Bool, autoremoveTimeout: CachedPeerAutoremoveTimeout, themeEmoticon: String?, photo: CachedPeerProfilePhoto, personalPhoto: CachedPeerProfilePhoto, fallbackPhoto: CachedPeerProfilePhoto, voiceMessagesAvailable: Bool, wallpaper: TelegramWallpaper?, flags: CachedUserFlags, businessHours: TelegramBusinessHours?, businessLocation: TelegramBusinessLocation?, greetingMessage: TelegramBusinessGreetingMessage?, awayMessage: TelegramBusinessAwayMessage?, connectedBot: TelegramAccountConnectedBot?, businessIntro: CachedTelegramBusinessIntro, birthday: TelegramBirthday?, personalChannel: CachedTelegramPersonalChannel, botPreview: BotPreview?, starGiftsCount: Int32?, starRefProgram: TelegramStarRefProgram?, verification: PeerVerification?, sendPaidMessageStars: StarsAmount?, disallowedGifts: TelegramDisallowedGifts) {
|
||||
public init(about: String?, botInfo: BotInfo?, editableBotInfo: EditableBotInfo?, peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, isBlocked: Bool, commonGroupCount: Int32, voiceCallsAvailable: Bool, videoCallsAvailable: Bool, callsPrivate: Bool, canPinMessages: Bool, hasScheduledMessages: Bool, autoremoveTimeout: CachedPeerAutoremoveTimeout, themeEmoticon: String?, photo: CachedPeerProfilePhoto, personalPhoto: CachedPeerProfilePhoto, fallbackPhoto: CachedPeerProfilePhoto, voiceMessagesAvailable: Bool, wallpaper: TelegramWallpaper?, flags: CachedUserFlags, businessHours: TelegramBusinessHours?, businessLocation: TelegramBusinessLocation?, greetingMessage: TelegramBusinessGreetingMessage?, awayMessage: TelegramBusinessAwayMessage?, connectedBot: TelegramAccountConnectedBot?, businessIntro: CachedTelegramBusinessIntro, birthday: TelegramBirthday?, personalChannel: CachedTelegramPersonalChannel, botPreview: BotPreview?, starGiftsCount: Int32?, starRefProgram: TelegramStarRefProgram?, verification: PeerVerification?, sendPaidMessageStars: StarsAmount?, disallowedGifts: TelegramDisallowedGifts?) {
|
||||
self.about = about
|
||||
self.botInfo = botInfo
|
||||
self.editableBotInfo = editableBotInfo
|
||||
@ -1153,7 +1153,7 @@ public final class CachedUserData: CachedPeerData {
|
||||
|
||||
self.sendPaidMessageStars = decoder.decodeCodable(StarsAmount.self, forKey: "sendPaidMessageStars")
|
||||
|
||||
self.disallowedGifts = TelegramDisallowedGifts(rawValue: decoder.decodeInt32ForKey("disallowedGifts", orElse: 0))
|
||||
self.disallowedGifts = decoder.decodeOptionalInt32ForKey("disallowedGifts").flatMap { TelegramDisallowedGifts(rawValue: $0) }
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
@ -1283,7 +1283,11 @@ public final class CachedUserData: CachedPeerData {
|
||||
encoder.encodeNil(forKey: "sendPaidMessageStars")
|
||||
}
|
||||
|
||||
encoder.encodeInt32(self.disallowedGifts.rawValue, forKey: "disallowedGifts")
|
||||
if let disallowedGifts = self.disallowedGifts {
|
||||
encoder.encodeInt32(disallowedGifts.rawValue, forKey: "disallowedGifts")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "disallowedGifts")
|
||||
}
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedPeerData) -> Bool {
|
||||
|
||||
@ -569,6 +569,75 @@ public extension TelegramEngine {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public func subscribe<
|
||||
T0: TelegramEngineDataItem,
|
||||
T1: TelegramEngineDataItem,
|
||||
T2: TelegramEngineDataItem,
|
||||
T3: TelegramEngineDataItem,
|
||||
T4: TelegramEngineDataItem,
|
||||
T5: TelegramEngineDataItem,
|
||||
T6: TelegramEngineDataItem,
|
||||
T7: TelegramEngineDataItem,
|
||||
T8: TelegramEngineDataItem,
|
||||
T9: TelegramEngineDataItem,
|
||||
T10: TelegramEngineDataItem
|
||||
>(
|
||||
_ t0: T0,
|
||||
_ t1: T1,
|
||||
_ t2: T2,
|
||||
_ t3: T3,
|
||||
_ t4: T4,
|
||||
_ t5: T5,
|
||||
_ t6: T6,
|
||||
_ t7: T7,
|
||||
_ t8: T8,
|
||||
_ t9: T9,
|
||||
_ t10: T10
|
||||
) -> Signal<
|
||||
(
|
||||
T0.Result,
|
||||
T1.Result,
|
||||
T2.Result,
|
||||
T3.Result,
|
||||
T4.Result,
|
||||
T5.Result,
|
||||
T6.Result,
|
||||
T7.Result,
|
||||
T8.Result,
|
||||
T9.Result,
|
||||
T10.Result
|
||||
),
|
||||
NoError> {
|
||||
return self._subscribe(items: [
|
||||
t0 as! AnyPostboxViewDataItem,
|
||||
t1 as! AnyPostboxViewDataItem,
|
||||
t2 as! AnyPostboxViewDataItem,
|
||||
t3 as! AnyPostboxViewDataItem,
|
||||
t4 as! AnyPostboxViewDataItem,
|
||||
t5 as! AnyPostboxViewDataItem,
|
||||
t6 as! AnyPostboxViewDataItem,
|
||||
t7 as! AnyPostboxViewDataItem,
|
||||
t8 as! AnyPostboxViewDataItem,
|
||||
t9 as! AnyPostboxViewDataItem,
|
||||
t10 as! AnyPostboxViewDataItem
|
||||
])
|
||||
|> map { results -> (T0.Result, T1.Result, T2.Result, T3.Result, T4.Result, T5.Result, T6.Result, T7.Result, T8.Result, T9.Result, T10.Result) in
|
||||
return (
|
||||
results[0] as! T0.Result,
|
||||
results[1] as! T1.Result,
|
||||
results[2] as! T2.Result,
|
||||
results[3] as! T3.Result,
|
||||
results[4] as! T4.Result,
|
||||
results[5] as! T5.Result,
|
||||
results[6] as! T6.Result,
|
||||
results[7] as! T7.Result,
|
||||
results[8] as! T8.Result,
|
||||
results[9] as! T9.Result,
|
||||
results[10] as! T10.Result
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func get<
|
||||
|
||||
@ -526,7 +526,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
}
|
||||
|
||||
func markAction(opaqueId: Data, media: Bool, fullscreen: Bool) {
|
||||
_internal_markAdAction(account: self.account, peerId: self.peerId, opaqueId: opaqueId, media: media, fullscreen: fullscreen)
|
||||
_internal_markAdAction(account: self.account, opaqueId: opaqueId, media: media, fullscreen: fullscreen)
|
||||
}
|
||||
|
||||
func remove(opaqueId: Data) {
|
||||
@ -601,7 +601,7 @@ public class AdMessagesHistoryContext {
|
||||
}
|
||||
|
||||
|
||||
func _internal_markAdAction(account: Account, peerId: EnginePeer.Id, opaqueId: Data, media: Bool, fullscreen: Bool) {
|
||||
func _internal_markAdAction(account: Account, opaqueId: Data, media: Bool, fullscreen: Bool) {
|
||||
var flags: Int32 = 0
|
||||
if media {
|
||||
flags |= (1 << 0)
|
||||
@ -616,3 +616,11 @@ func _internal_markAdAction(account: Account, peerId: EnginePeer.Id, opaqueId: D
|
||||
|> ignoreValues
|
||||
let _ = signal.start()
|
||||
}
|
||||
|
||||
func _internal_markAsSeen(account: Account, opaqueId: Data) -> Signal<Never, NoError> {
|
||||
return account.network.request(Api.functions.messages.viewSponsoredMessage(randomId: Buffer(data: opaqueId)))
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
|
||||
@ -1125,6 +1125,23 @@ public struct TelegramBusinessBotRights: OptionSet, Codable {
|
||||
public static let transferStars = TelegramBusinessBotRights(rawValue: 1 << 12)
|
||||
public static let manageStories = TelegramBusinessBotRights(rawValue: 1 << 13)
|
||||
|
||||
public static let All: TelegramBusinessBotRights = [
|
||||
.reply,
|
||||
.readMessages,
|
||||
.deleteSentMessages,
|
||||
.deleteReceivedMessages,
|
||||
.editName,
|
||||
.editBio,
|
||||
.editProfilePhoto,
|
||||
.editUsername,
|
||||
.viewGifts,
|
||||
.sellGifts,
|
||||
.changeGiftSettings,
|
||||
.transferAndUpgradeGifts,
|
||||
.transferStars,
|
||||
.manageStories
|
||||
]
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
let value = try? container.decode(Int32.self, forKey: "v")
|
||||
|
||||
@ -19,7 +19,7 @@ public enum ReportAdMessageError {
|
||||
case premiumRequired
|
||||
}
|
||||
|
||||
func _internal_reportAdMessage(account: Account, peerId: EnginePeer.Id, opaqueId: Data, option: Data?) -> Signal<ReportAdMessageResult, ReportAdMessageError> {
|
||||
func _internal_reportAdMessage(account: Account, opaqueId: Data, option: Data?) -> Signal<ReportAdMessageResult, ReportAdMessageError> {
|
||||
return account.network.request(Api.functions.messages.reportSponsoredMessage(randomId: Buffer(data: opaqueId), option: Buffer(data: option)))
|
||||
|> mapError { error -> ReportAdMessageError in
|
||||
if error.errorDescription == "PREMIUM_ACCOUNT_REQUIRED" {
|
||||
|
||||
@ -1504,8 +1504,8 @@ public extension TelegramEngine {
|
||||
}).startStandalone()
|
||||
}
|
||||
|
||||
public func reportAdMessage(peerId: EnginePeer.Id, opaqueId: Data, option: Data?) -> Signal<ReportAdMessageResult, ReportAdMessageError> {
|
||||
return _internal_reportAdMessage(account: self.account, peerId: peerId, opaqueId: opaqueId, option: option)
|
||||
public func reportAdMessage(opaqueId: Data, option: Data?) -> Signal<ReportAdMessageResult, ReportAdMessageError> {
|
||||
return _internal_reportAdMessage(account: self.account, opaqueId: opaqueId, option: option)
|
||||
}
|
||||
|
||||
public func reportContent(subject: ReportContentSubject, option: Data?, message: String?) -> Signal<ReportContentResult, ReportContentError> {
|
||||
@ -1516,8 +1516,8 @@ public extension TelegramEngine {
|
||||
return _internal_updateExtendedMedia(account: self.account, messageIds: messageIds)
|
||||
}
|
||||
|
||||
public func markAdAction(peerId: EnginePeer.Id, opaqueId: Data, media: Bool, fullscreen: Bool) {
|
||||
_internal_markAdAction(account: self.account, peerId: peerId, opaqueId: opaqueId, media: media, fullscreen: fullscreen)
|
||||
public func markAdAction(opaqueId: Data, media: Bool, fullscreen: Bool) {
|
||||
_internal_markAdAction(account: self.account, opaqueId: opaqueId, media: media, fullscreen: fullscreen)
|
||||
}
|
||||
|
||||
public func getAllLocalChannels(count: Int) -> Signal<[EnginePeer.Id], NoError> {
|
||||
|
||||
@ -445,9 +445,12 @@ private func _internal_requestStarsSubscriptions(account: Account, peerId: Engin
|
||||
flags |= (1 << 0)
|
||||
}
|
||||
return account.network.request(Api.functions.payments.getStarsSubscriptions(flags: flags, peer: inputPeer, offset: offset))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> castError(RequestStarsSubscriptionsError.self)
|
||||
|> mapToSignal { result -> Signal<InternalStarsStatus, RequestStarsSubscriptionsError> in
|
||||
guard let result else {
|
||||
return .single(InternalStarsStatus(balance: .zero, subscriptionsMissingBalance: nil, subscriptions: [], nextSubscriptionsOffset: nil, transactions: [], nextTransactionsOffset: nil))
|
||||
}
|
||||
return account.postbox.transaction { transaction -> InternalStarsStatus in
|
||||
switch result {
|
||||
case let .starsStatus(_, balance, subscriptions, subscriptionsNextOffset, subscriptionsMissingBalance, _, _, chats, users):
|
||||
|
||||
@ -6,12 +6,14 @@ import TelegramApi
|
||||
public class AdPeer: Equatable {
|
||||
public let opaqueId: Data
|
||||
public let peer: EnginePeer
|
||||
public let subscribers: Int32?
|
||||
public let sponsorInfo: String?
|
||||
public let additionalInfo: String?
|
||||
|
||||
public init(opaqueId: Data, peer: EnginePeer, sponsorInfo: String?, additionalInfo: String?) {
|
||||
public init(opaqueId: Data, peer: EnginePeer, subscribers: Int32?, sponsorInfo: String?, additionalInfo: String?) {
|
||||
self.opaqueId = opaqueId
|
||||
self.peer = peer
|
||||
self.subscribers = subscribers
|
||||
self.sponsorInfo = sponsorInfo
|
||||
self.additionalInfo = additionalInfo
|
||||
}
|
||||
@ -23,6 +25,9 @@ public class AdPeer: Equatable {
|
||||
if lhs.peer != rhs.peer {
|
||||
return false
|
||||
}
|
||||
if lhs.subscribers != rhs.subscribers {
|
||||
return false
|
||||
}
|
||||
if lhs.sponsorInfo != rhs.sponsorInfo {
|
||||
return false
|
||||
}
|
||||
@ -49,17 +54,32 @@ func _internal_searchAdPeers(account: Account, query: String) -> Signal<[AdPeer]
|
||||
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
|
||||
updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: parsedPeers)
|
||||
|
||||
var subscribers: [PeerId: Int32] = [:]
|
||||
for chat in chats {
|
||||
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||
switch chat {
|
||||
case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _, _, _, _):
|
||||
if let participantsCount = participantsCount {
|
||||
subscribers[groupOrChannel.id] = participantsCount
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var result: [AdPeer] = []
|
||||
for peer in peers {
|
||||
switch peer {
|
||||
case let .sponsoredPeer(_, randomId, apiPeer, sponsorInfo, additionalInfo):
|
||||
guard let peer = parsedPeers.peers[apiPeer.peerId] else {
|
||||
guard let peer = parsedPeers.get(apiPeer.peerId) else {
|
||||
continue
|
||||
}
|
||||
result.append(
|
||||
AdPeer(
|
||||
opaqueId: randomId.makeData(),
|
||||
peer: EnginePeer(peer),
|
||||
subscribers: subscribers[peer.id],
|
||||
sponsorInfo: sponsorInfo,
|
||||
additionalInfo: additionalInfo
|
||||
)
|
||||
|
||||
@ -548,8 +548,11 @@ func _internal_adminedPublicChannels(account: Account, scope: AdminedPublicChann
|
||||
let accountPeerId = account.peerId
|
||||
|
||||
return account.network.request(Api.functions.channels.getAdminedPublicChannels(flags: flags))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[TelegramAdminedPublicChannel], NoError> in
|
||||
guard let result else {
|
||||
return .single([])
|
||||
}
|
||||
return account.postbox.transaction { transaction -> [TelegramAdminedPublicChannel] in
|
||||
let chats: [Api.Chat]
|
||||
var subscriberCounts: [PeerId: Int] = [:]
|
||||
@ -675,8 +678,11 @@ func _internal_channelsForPublicReaction(account: Account, useLocalCache: Bool)
|
||||
}
|
||||
|> mapToSignal { cachedPeers in
|
||||
let remote: Signal<[Peer], NoError> = account.network.request(Api.functions.channels.getAdminedPublicChannels(flags: 0))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[Peer], NoError> in
|
||||
guard let result else {
|
||||
return .single([])
|
||||
}
|
||||
return account.postbox.transaction { transaction -> [Peer] in
|
||||
let chats: [Api.Chat]
|
||||
let parsedPeers: AccumulatedPeers
|
||||
|
||||
@ -114,8 +114,11 @@ func _internal_updateBirthday(account: Account, birthday: TelegramBirthday?) ->
|
||||
|
||||
func managedContactBirthdays(stateManager: AccountStateManager) -> Signal<Never, NoError> {
|
||||
let poll = stateManager.network.request(Api.functions.contacts.getBirthdays())
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<Never, NoError> in
|
||||
guard let result else {
|
||||
return .complete()
|
||||
}
|
||||
return stateManager.postbox.transaction { transaction -> Void in
|
||||
if case let .contactBirthdays(contactBirthdays, users) = result {
|
||||
updatePeers(transaction: transaction, accountPeerId: stateManager.accountPeerId, peers: AccumulatedPeers(users: users))
|
||||
|
||||
@ -84,35 +84,38 @@ func _internal_channelMembers(postbox: Postbox, network: Network, accountPeerId:
|
||||
}
|
||||
}
|
||||
return network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: apiFilter, offset: offset, limit: limit, hash: hash))
|
||||
|> retryRequest
|
||||
|> mapToSignal { result -> Signal<[RenderedChannelParticipant]?, NoError> in
|
||||
return postbox.transaction { transaction -> [RenderedChannelParticipant]? in
|
||||
var items: [RenderedChannelParticipant] = []
|
||||
switch result {
|
||||
case let .channelParticipants(_, participants, chats, users):
|
||||
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
|
||||
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
|
||||
var peers: [PeerId: Peer] = [:]
|
||||
for id in parsedPeers.allIds {
|
||||
if let peer = transaction.getPeer(id) {
|
||||
peers[peer.id] = peer
|
||||
}
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[RenderedChannelParticipant]?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
return postbox.transaction { transaction -> [RenderedChannelParticipant]? in
|
||||
var items: [RenderedChannelParticipant] = []
|
||||
switch result {
|
||||
case let .channelParticipants(_, participants, chats, users):
|
||||
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
|
||||
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
|
||||
var peers: [PeerId: Peer] = [:]
|
||||
for id in parsedPeers.allIds {
|
||||
if let peer = transaction.getPeer(id) {
|
||||
peers[peer.id] = peer
|
||||
}
|
||||
|
||||
for participant in CachedChannelParticipants(apiParticipants: participants).participants {
|
||||
if let peer = parsedPeers.get(participant.peerId) {
|
||||
var renderedPresences: [PeerId: PeerPresence] = [:]
|
||||
if let presence = transaction.getPeerPresence(peerId: participant.peerId) {
|
||||
renderedPresences[participant.peerId] = presence
|
||||
}
|
||||
items.append(RenderedChannelParticipant(participant: participant, peer: peer, peers: peers, presences: renderedPresences))
|
||||
}
|
||||
|
||||
for participant in CachedChannelParticipants(apiParticipants: participants).participants {
|
||||
if let peer = parsedPeers.get(participant.peerId) {
|
||||
var renderedPresences: [PeerId: PeerPresence] = [:]
|
||||
if let presence = transaction.getPeerPresence(peerId: participant.peerId) {
|
||||
renderedPresences[participant.peerId] = presence
|
||||
}
|
||||
items.append(RenderedChannelParticipant(participant: participant, peer: peer, peers: peers, presences: renderedPresences))
|
||||
}
|
||||
case .channelParticipantsNotModified:
|
||||
return nil
|
||||
}
|
||||
return items
|
||||
}
|
||||
case .channelParticipantsNotModified:
|
||||
return nil
|
||||
}
|
||||
return items
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .single([])
|
||||
|
||||
@ -27,8 +27,11 @@ func _internal_notificationExceptionsList(accountPeerId: PeerId, postbox: Postbo
|
||||
}
|
||||
|
||||
return network.request(Api.functions.account.getNotifyExceptions(flags: flags, peer: nil))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<NotificationExceptionsList, NoError> in
|
||||
guard let result else {
|
||||
return .single(NotificationExceptionsList(peers: [:], settings: [:]))
|
||||
}
|
||||
return postbox.transaction { transaction -> NotificationExceptionsList in
|
||||
switch result {
|
||||
case let .updates(updates, users, chats, _, _):
|
||||
|
||||
@ -151,7 +151,7 @@ func _internal_updateRecentPeersEnabled(postbox: Postbox, network: Network, enab
|
||||
|
||||
func _internal_managedRecentlyUsedInlineBots(postbox: Postbox, network: Network, accountPeerId: PeerId) -> Signal<Void, NoError> {
|
||||
let remotePeers = network.request(Api.functions.contacts.getTopPeers(flags: 1 << 2, offset: 0, limit: 16, hash: 0))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> map { result -> (AccumulatedPeers, [(PeerId, Double)])? in
|
||||
switch result {
|
||||
case .topPeersDisabled:
|
||||
@ -174,6 +174,8 @@ func _internal_managedRecentlyUsedInlineBots(postbox: Postbox, network: Network,
|
||||
return (parsedPeers, peersWithRating)
|
||||
case .topPeersNotModified:
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
return (AccumulatedPeers(), [])
|
||||
}
|
||||
|
||||
@ -1530,6 +1530,10 @@ public extension TelegramEngine {
|
||||
return _internal_searchAdPeers(account: self.account, query: query)
|
||||
}
|
||||
|
||||
public func markAsSeen(ad opaqueId: Data) -> Signal<Never, NoError> {
|
||||
return _internal_markAsSeen(account: self.account, opaqueId: opaqueId)
|
||||
}
|
||||
|
||||
public func isPremiumRequiredToContact(_ peerIds: [EnginePeer.Id]) -> Signal<[EnginePeer.Id: RequirementToContact], NoError> {
|
||||
return _internal_updateIsPremiumRequiredToContact(account: self.account, peerIds: peerIds)
|
||||
}
|
||||
|
||||
@ -76,8 +76,11 @@ func fetchAndUpdateSupplementalCachedPeerData(peerId rawPeerId: PeerId, accountP
|
||||
}
|
||||
} else if let inputPeer = apiInputPeer(peer) {
|
||||
return network.request(Api.functions.messages.getPeerSettings(peer: inputPeer))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { peerSettings -> Signal<Bool, NoError> in
|
||||
guard let peerSettings else {
|
||||
return .single(false)
|
||||
}
|
||||
return postbox.transaction { transaction -> Bool in
|
||||
let parsedPeers: AccumulatedPeers
|
||||
|
||||
@ -397,7 +400,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
||||
let sendPaidMessageStars = sendPaidMessageStars.flatMap { StarsAmount(value: $0, nanos: 0) }
|
||||
|
||||
var disallowedGifts: TelegramDisallowedGifts = []
|
||||
if case let .disallowedStarGiftsSettings(giftFlags) = disallowedStarGifts {
|
||||
if case let .disallowedGiftsSettings(giftFlags) = disallowedStarGifts {
|
||||
if (giftFlags & (1 << 0)) != 0 {
|
||||
disallowedGifts.insert(.unlimited)
|
||||
}
|
||||
@ -407,6 +410,9 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
||||
if (giftFlags & (1 << 2)) != 0 {
|
||||
disallowedGifts.insert(.unique)
|
||||
}
|
||||
if (giftFlags & (1 << 3)) != 0 {
|
||||
disallowedGifts.insert(.premium)
|
||||
}
|
||||
}
|
||||
|
||||
return previous.withUpdatedAbout(userFullAbout)
|
||||
@ -451,8 +457,11 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
||||
}
|
||||
} else if peerId.namespace == Namespaces.Peer.CloudGroup {
|
||||
return network.request(Api.functions.messages.getFullChat(chatId: peerId.id._internalGetInt64Value()))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<Bool, NoError> in
|
||||
guard let result else {
|
||||
return .single(false)
|
||||
}
|
||||
return postbox.transaction { transaction -> Bool in
|
||||
switch result {
|
||||
case let .chatFull(fullChat, chats, users):
|
||||
|
||||
@ -78,8 +78,11 @@ public final class BlockedPeersContext {
|
||||
}
|
||||
|
||||
self.disposable.set((self.account.network.request(Api.functions.contacts.getBlocked(flags: flags, offset: Int32(self._state.peers.count), limit: limit))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<(peers: [RenderedPeer], canLoadMore: Bool, totalCount: Int?), NoError> in
|
||||
guard let result else {
|
||||
return .single((peers: [], canLoadMore: false, totalCount: 0))
|
||||
}
|
||||
return postbox.transaction { transaction -> (peers: [RenderedPeer], canLoadMore: Bool, totalCount: Int?) in
|
||||
switch result {
|
||||
case let .blocked(blocked, chats, users):
|
||||
|
||||
@ -5,8 +5,11 @@ import SwiftSignalKit
|
||||
|
||||
func requestRecentAccountSessions(account: Account) -> Signal<([RecentAccountSession], Int32), NoError> {
|
||||
return account.network.request(Api.functions.account.getAuthorizations())
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> map { result -> ([RecentAccountSession], Int32) in
|
||||
guard let result else {
|
||||
return ([], 1)
|
||||
}
|
||||
var sessions: [RecentAccountSession] = []
|
||||
var ttlDays: Int32 = 1
|
||||
switch result {
|
||||
|
||||
@ -22,25 +22,28 @@ public struct WebAuthorization : Equatable {
|
||||
|
||||
func webSessions(network: Network) -> Signal<([WebAuthorization], [PeerId: Peer]), NoError> {
|
||||
return network.request(Api.functions.account.getWebAuthorizations())
|
||||
|> retryRequest
|
||||
|> map { result -> ([WebAuthorization], [PeerId : Peer]) in
|
||||
var sessions: [WebAuthorization] = []
|
||||
var peers:[PeerId : Peer] = [:]
|
||||
switch result {
|
||||
case let .webAuthorizations(authorizations, users):
|
||||
for authorization in authorizations {
|
||||
switch authorization {
|
||||
case let .webAuthorization(hash, botId, domain, browser, platform, dateCreated, dateActive, ip, region):
|
||||
sessions.append(WebAuthorization(hash: hash, botId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId)), domain: domain, browser: browser, platform: platform, dateCreated: dateCreated, dateActive: dateActive, ip: ip, region: region))
|
||||
|
||||
}
|
||||
}
|
||||
for user in users {
|
||||
let peer = TelegramUser(user: user)
|
||||
peers[peer.id] = peer
|
||||
|> retryRequestIfNotFrozen
|
||||
|> map { result -> ([WebAuthorization], [PeerId : Peer]) in
|
||||
guard let result else {
|
||||
return ([], [:])
|
||||
}
|
||||
var sessions: [WebAuthorization] = []
|
||||
var peers:[PeerId : Peer] = [:]
|
||||
switch result {
|
||||
case let .webAuthorizations(authorizations, users):
|
||||
for authorization in authorizations {
|
||||
switch authorization {
|
||||
case let .webAuthorization(hash, botId, domain, browser, platform, dateCreated, dateActive, ip, region):
|
||||
sessions.append(WebAuthorization(hash: hash, botId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId)), domain: domain, browser: browser, platform: platform, dateCreated: dateCreated, dateActive: dateActive, ip: ip, region: region))
|
||||
|
||||
}
|
||||
}
|
||||
return (sessions, peers)
|
||||
for user in users {
|
||||
let peer = TelegramUser(user: user)
|
||||
peers[peer.id] = peer
|
||||
}
|
||||
}
|
||||
return (sessions, peers)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@ func _internal_updateGlobalPrivacySettings(account: Account) -> Signal<Never, No
|
||||
}
|
||||
|
||||
var disallowedGifts: TelegramDisallowedGifts = []
|
||||
if case let .disallowedStarGiftsSettings(giftFlags) = disallowedStarGifts {
|
||||
if case let .disallowedGiftsSettings(giftFlags) = disallowedStarGifts {
|
||||
if (giftFlags & (1 << 0)) != 0 {
|
||||
disallowedGifts.insert(.unlimited)
|
||||
}
|
||||
@ -44,6 +44,9 @@ func _internal_updateGlobalPrivacySettings(account: Account) -> Signal<Never, No
|
||||
if (giftFlags & (1 << 2)) != 0 {
|
||||
disallowedGifts.insert(.unique)
|
||||
}
|
||||
if (giftFlags & (1 << 3)) != 0 {
|
||||
disallowedGifts.insert(.premium)
|
||||
}
|
||||
}
|
||||
|
||||
globalSettings = GlobalPrivacySettings(
|
||||
@ -256,7 +259,7 @@ func _internal_requestAccountPrivacySettings(account: Account) -> Signal<Account
|
||||
}
|
||||
|
||||
var disallowedGifts: TelegramDisallowedGifts = []
|
||||
if case let .disallowedStarGiftsSettings(giftFlags) = disallowedStarGifts {
|
||||
if case let .disallowedGiftsSettings(giftFlags) = disallowedStarGifts {
|
||||
if (giftFlags & (1 << 0)) != 0 {
|
||||
disallowedGifts.insert(.unlimited)
|
||||
}
|
||||
@ -266,6 +269,9 @@ func _internal_requestAccountPrivacySettings(account: Account) -> Signal<Account
|
||||
if (giftFlags & (1 << 2)) != 0 {
|
||||
disallowedGifts.insert(.unique)
|
||||
}
|
||||
if (giftFlags & (1 << 3)) != 0 {
|
||||
disallowedGifts.insert(.premium)
|
||||
}
|
||||
}
|
||||
|
||||
globalSettings = GlobalPrivacySettings(
|
||||
@ -407,12 +413,15 @@ func _internal_updateGlobalPrivacySettings(account: Account, settings: GlobalPri
|
||||
if settings.disallowedGifts.contains(.unique) {
|
||||
giftFlags |= 1 << 2
|
||||
}
|
||||
if settings.disallowedGifts.contains(.premium) {
|
||||
giftFlags |= 1 << 3
|
||||
}
|
||||
}
|
||||
flags |= 1 << 6
|
||||
let disallowedStargifts = Api.DisallowedStarGiftsSettings.disallowedStarGiftsSettings(flags: giftFlags)
|
||||
let disallowedStargifts = Api.DisallowedGiftsSettings.disallowedGiftsSettings(flags: giftFlags)
|
||||
|
||||
return account.network.request(Api.functions.account.setGlobalPrivacySettings(
|
||||
settings: .globalPrivacySettings(flags: flags, noncontactPeersPaidStars: noncontactPeersPaidStars, disallowedStargifts: disallowedStargifts)
|
||||
settings: .globalPrivacySettings(flags: flags, noncontactPeersPaidStars: noncontactPeersPaidStars, disallowedGifts: disallowedStargifts)
|
||||
))
|
||||
|> retryRequest
|
||||
|> ignoreValues
|
||||
|
||||
@ -34,8 +34,11 @@ public final class ChatThemes: Codable, Equatable {
|
||||
func _internal_getChatThemes(accountManager: AccountManager<TelegramAccountManagerTypes>, network: Network, forceUpdate: Bool = false, onlyCached: Bool = false) -> Signal<[TelegramTheme], NoError> {
|
||||
let fetch: ([TelegramTheme]?, Int64?) -> Signal<[TelegramTheme], NoError> = { current, hash in
|
||||
return network.request(Api.functions.account.getChatThemes(hash: hash ?? 0))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<[TelegramTheme], NoError> in
|
||||
guard let result else {
|
||||
return .complete()
|
||||
}
|
||||
switch result {
|
||||
case let .themes(hash, apiThemes):
|
||||
let result = apiThemes.compactMap { TelegramTheme(apiTheme: $0) }
|
||||
|
||||
@ -7,8 +7,11 @@ import TelegramApi
|
||||
public func telegramWallpapers(postbox: Postbox, network: Network, forceUpdate: Bool = false) -> Signal<[TelegramWallpaper], NoError> {
|
||||
let fetch: ([TelegramWallpaper]?, Int64?) -> Signal<[TelegramWallpaper], NoError> = { current, hash in
|
||||
network.request(Api.functions.account.getWallPapers(hash: hash ?? 0))
|
||||
|> retryRequest
|
||||
|> retryRequestIfNotFrozen
|
||||
|> mapToSignal { result -> Signal<([TelegramWallpaper], Int64), NoError> in
|
||||
guard let result else {
|
||||
return .single(([], -1))
|
||||
}
|
||||
switch result {
|
||||
case let .wallPapers(hash, wallpapers):
|
||||
var items: [TelegramWallpaper] = []
|
||||
|
||||
@ -43,6 +43,7 @@ public enum PresentationResourceKey: Int32 {
|
||||
case itemListDisclosureLocked
|
||||
case itemListCheckIcon
|
||||
case itemListSecondaryCheckIcon
|
||||
case itemListDisabledCheckIcon
|
||||
case itemListPlusIcon
|
||||
case itemListRoundPlusIcon
|
||||
case itemListAccentDeleteIcon
|
||||
|
||||
@ -57,6 +57,12 @@ public struct PresentationResourcesItemList {
|
||||
})
|
||||
}
|
||||
|
||||
public static func disabledCheckIconImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.itemListDisabledCheckIcon.rawValue, { theme in
|
||||
return generateItemListCheckIcon(color: theme.list.itemDisabledTextColor)
|
||||
})
|
||||
}
|
||||
|
||||
public static func plusIconImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.itemListPlusIcon.rawValue, { theme in
|
||||
return generateItemListPlusIcon(theme.list.itemAccentColor)
|
||||
|
||||
@ -193,10 +193,9 @@ private final class ScrollContent: CombinedComponent {
|
||||
adsText = strings.AdsInfo_Bot_Ads_Text
|
||||
infoRawText = strings.AdsInfo_Bot_Launch_Text
|
||||
case .search:
|
||||
//TODO:localize
|
||||
respectText = "Ads like this do not use your personal information and are based on the search query you entered."
|
||||
adsText = strings.AdsInfo_Bot_Ads_Text
|
||||
infoRawText = "Anyone can create an ad to display in search results for any query. Check out the Telegram Ad Platform for details. [Learn More >]()"
|
||||
respectText = strings.AdsInfo_Search_Respect_Text
|
||||
adsText = strings.AdsInfo_Search_Ads_Text
|
||||
infoRawText = strings.AdsInfo_Search_Launch_Text
|
||||
}
|
||||
|
||||
var items: [AnyComponentWithIdentity<Empty>] = []
|
||||
@ -1277,22 +1276,19 @@ public class AdsInfoScreen: ViewController {
|
||||
guard let navigationController = self?.controller?.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
|
||||
self?.controller?.dismiss(animated: true)
|
||||
|
||||
let _ = (context.engine.messages.reportAdMessage(peerId: message.id.peerId, opaqueId: adAttribute.opaqueId, option: nil)
|
||||
|
||||
let _ = (context.engine.messages.reportAdMessage(opaqueId: adAttribute.opaqueId, option: nil)
|
||||
|> deliverOnMainQueue).start(next: { [weak navigationController] result in
|
||||
if case let .options(title, options) = result {
|
||||
Queue.mainQueue().after(0.2) {
|
||||
navigationController?.pushViewController(
|
||||
AdsReportScreen(
|
||||
context: context,
|
||||
peerId: message.id.peerId,
|
||||
opaqueId: adAttribute.opaqueId,
|
||||
title: title,
|
||||
options: options,
|
||||
completed: {
|
||||
removeAd?(adAttribute.opaqueId)
|
||||
// removeAd?(adAttribute.opaqueId)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@ -250,7 +250,6 @@ private final class SheetContent: CombinedComponent {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
|
||||
let context: AccountContext
|
||||
let peerId: EnginePeer.Id
|
||||
let opaqueId: Data
|
||||
let title: String
|
||||
let options: [ReportAdMessageResult.Option]
|
||||
@ -262,7 +261,6 @@ private final class SheetContent: CombinedComponent {
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
peerId: EnginePeer.Id,
|
||||
opaqueId: Data,
|
||||
title: String,
|
||||
options: [ReportAdMessageResult.Option],
|
||||
@ -273,7 +271,6 @@ private final class SheetContent: CombinedComponent {
|
||||
update: @escaping (ComponentTransition) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.peerId = peerId
|
||||
self.opaqueId = opaqueId
|
||||
self.title = title
|
||||
self.options = options
|
||||
@ -288,9 +285,6 @@ private final class SheetContent: CombinedComponent {
|
||||
if lhs.context !== rhs.context {
|
||||
return false
|
||||
}
|
||||
if lhs.peerId != rhs.peerId {
|
||||
return false
|
||||
}
|
||||
if lhs.opaqueId != rhs.opaqueId {
|
||||
return false
|
||||
}
|
||||
@ -329,7 +323,6 @@ private final class SheetContent: CombinedComponent {
|
||||
let update = component.update
|
||||
|
||||
let accountContext = component.context
|
||||
let peerId = component.peerId
|
||||
let opaqueId = component.opaqueId
|
||||
let complete = component.complete
|
||||
let action: (SheetPageContent.Item) -> Void = { [weak state] item in
|
||||
@ -337,7 +330,7 @@ private final class SheetContent: CombinedComponent {
|
||||
return
|
||||
}
|
||||
state.disposable.set(
|
||||
(accountContext.engine.messages.reportAdMessage(peerId: peerId, opaqueId: opaqueId, option: item.option)
|
||||
(accountContext.engine.messages.reportAdMessage(opaqueId: opaqueId, option: item.option)
|
||||
|> deliverOnMainQueue).start(next: { [weak state] result in
|
||||
switch result {
|
||||
case let .options(title, options):
|
||||
@ -423,7 +416,6 @@ private final class SheetContainerComponent: CombinedComponent {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
|
||||
let context: AccountContext
|
||||
let peerId: EnginePeer.Id
|
||||
let opaqueId: Data
|
||||
let title: String
|
||||
let options: [ReportAdMessageResult.Option]
|
||||
@ -432,7 +424,6 @@ private final class SheetContainerComponent: CombinedComponent {
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
peerId: EnginePeer.Id,
|
||||
opaqueId: Data,
|
||||
title: String,
|
||||
options: [ReportAdMessageResult.Option],
|
||||
@ -440,7 +431,6 @@ private final class SheetContainerComponent: CombinedComponent {
|
||||
complete: @escaping (ReportResult) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.peerId = peerId
|
||||
self.opaqueId = opaqueId
|
||||
self.title = title
|
||||
self.options = options
|
||||
@ -452,9 +442,6 @@ private final class SheetContainerComponent: CombinedComponent {
|
||||
if lhs.context !== rhs.context {
|
||||
return false
|
||||
}
|
||||
if lhs.peerId != rhs.peerId {
|
||||
return false
|
||||
}
|
||||
if lhs.opaqueId != rhs.opaqueId {
|
||||
return false
|
||||
}
|
||||
@ -490,7 +477,6 @@ private final class SheetContainerComponent: CombinedComponent {
|
||||
component: SheetComponent<EnvironmentType>(
|
||||
content: AnyComponent<EnvironmentType>(SheetContent(
|
||||
context: context.component.context,
|
||||
peerId: context.component.peerId,
|
||||
opaqueId: context.component.opaqueId,
|
||||
title: context.component.title,
|
||||
options: context.component.options,
|
||||
@ -571,7 +557,6 @@ public final class AdsReportScreen: ViewControllerComponentContainer {
|
||||
|
||||
public init(
|
||||
context: AccountContext,
|
||||
peerId: EnginePeer.Id,
|
||||
opaqueId: Data,
|
||||
title: String,
|
||||
options: [ReportAdMessageResult.Option],
|
||||
@ -585,7 +570,6 @@ public final class AdsReportScreen: ViewControllerComponentContainer {
|
||||
context: context,
|
||||
component: SheetContainerComponent(
|
||||
context: context,
|
||||
peerId: peerId,
|
||||
opaqueId: opaqueId,
|
||||
title: title,
|
||||
options: options,
|
||||
|
||||
@ -686,7 +686,7 @@ public final class ChatInlineSearchResultsListComponent: Component {
|
||||
},
|
||||
openPhotoSetup: {
|
||||
},
|
||||
openAdInfo: { _ in
|
||||
openAdInfo: { _, _ in
|
||||
},
|
||||
openAccountFreezeInfo: {
|
||||
}
|
||||
|
||||
@ -69,11 +69,19 @@ public final class GiftItemComponent: Component {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum Font {
|
||||
case generic
|
||||
case monospaced
|
||||
}
|
||||
|
||||
public let text: String
|
||||
public let font: Font
|
||||
public let color: Color
|
||||
|
||||
public init(text: String, color: Color) {
|
||||
public init(text: String, font: Font = .generic, color: Color) {
|
||||
self.text = text
|
||||
self.font = font
|
||||
self.color = color
|
||||
}
|
||||
}
|
||||
@ -593,11 +601,19 @@ public final class GiftItemComponent: Component {
|
||||
} else {
|
||||
ribbonFontSize = 10.0
|
||||
}
|
||||
let ribbonFont: UIFont
|
||||
switch ribbon.font {
|
||||
case .generic:
|
||||
ribbonFont = Font.semibold(ribbonFontSize)
|
||||
case .monospaced:
|
||||
ribbonFont = Font.with(size: 10.0, design: .monospace, weight: .semibold)
|
||||
}
|
||||
|
||||
let ribbonTextSize = self.ribbonText.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(
|
||||
MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(string: ribbon.text, font: Font.semibold(ribbonFontSize), textColor: .white)),
|
||||
text: .plain(NSAttributedString(string: ribbon.text, font: ribbonFont, textColor: .white)),
|
||||
horizontalAlignment: .center
|
||||
)
|
||||
),
|
||||
@ -778,7 +794,11 @@ public final class GiftItemComponent: Component {
|
||||
} else {
|
||||
selectionLayer = SimpleShapeLayer()
|
||||
self.selectionLayer = selectionLayer
|
||||
self.layer.addSublayer(selectionLayer)
|
||||
if self.ribbon.layer.superlayer != nil {
|
||||
self.layer.insertSublayer(selectionLayer, below: self.ribbon.layer)
|
||||
} else {
|
||||
self.layer.addSublayer(selectionLayer)
|
||||
}
|
||||
|
||||
selectionLayer.fillColor = UIColor.clear.cgColor
|
||||
selectionLayer.strokeColor = UIColor.white.cgColor
|
||||
|
||||
@ -430,10 +430,15 @@ final class GiftOptionsScreenComponent: Component {
|
||||
)
|
||||
mainController.push(giftController)
|
||||
} else {
|
||||
var forceUnique = false
|
||||
if let disallowedGifts = self.state?.disallowedGifts, disallowedGifts.contains(.limited) && !disallowedGifts.contains(.unique) {
|
||||
forceUnique = true
|
||||
}
|
||||
|
||||
let giftController = GiftSetupScreen(
|
||||
context: component.context,
|
||||
peerId: component.peerId,
|
||||
subject: .starGift(gift),
|
||||
subject: .starGift(gift, forceUnique),
|
||||
completion: component.completion
|
||||
)
|
||||
mainController.push(giftController)
|
||||
@ -687,6 +692,10 @@ final class GiftOptionsScreenComponent: Component {
|
||||
}
|
||||
self.component = component
|
||||
|
||||
if let disallowedGifts = self.state?.disallowedGifts, disallowedGifts == .All {
|
||||
controller()?.dismiss()
|
||||
}
|
||||
|
||||
if (state.starGifts ?? []).isEmpty && !(state.transferStarGifts ?? []).isEmpty {
|
||||
self.starsFilter = .transfer
|
||||
}
|
||||
@ -714,7 +723,7 @@ final class GiftOptionsScreenComponent: Component {
|
||||
|
||||
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: component.context.currentAppConfiguration.with { $0 })
|
||||
|
||||
let isPremiumDisabled = premiumConfiguration.isPremiumDisabled
|
||||
let isPremiumDisabled = premiumConfiguration.isPremiumDisabled || state.disallowedGifts?.contains(.premium) == true
|
||||
let isSelfGift = component.peerId == component.context.account.peerId
|
||||
let isChannelGift = component.peerId.namespace == Namespaces.Peer.CloudChannel
|
||||
|
||||
@ -1339,19 +1348,26 @@ final class GiftOptionsScreenComponent: Component {
|
||||
self.disposable = combineLatest(
|
||||
queue: Queue.mainQueue(),
|
||||
context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer.init(id: peerId),
|
||||
TelegramEngine.EngineData.Item.Peer.Peer.init(id: peerId)
|
||||
),
|
||||
context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Peer.DisallowedGifts(id: peerId)
|
||||
),
|
||||
availableProducts,
|
||||
context.engine.payments.cachedStarGifts(),
|
||||
self.starGiftsContext.state
|
||||
).start(next: { [weak self] data, availableProducts, starGifts, profileGiftsState in
|
||||
).start(next: { [weak self] peer, disallowedGifts, availableProducts, starGifts, profileGiftsState in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.peer = data.0
|
||||
self.disallowedGifts = data.1 ?? []
|
||||
|
||||
if disallowedGifts == nil && self.peer == nil, case .user = peer {
|
||||
let _ = context.engine.peers.fetchAndUpdateCachedPeerData(peerId: peerId).startStandalone()
|
||||
}
|
||||
|
||||
self.peer = peer
|
||||
self.disallowedGifts = disallowedGifts ?? []
|
||||
|
||||
if peerId != context.account.peerId {
|
||||
if availableProducts.isEmpty {
|
||||
var premiumProducts: [PremiumGiftProduct] = []
|
||||
@ -1425,7 +1441,11 @@ final class GiftOptionsScreenComponent: Component {
|
||||
}
|
||||
if disallowedGifts.contains(.limited) {
|
||||
if gift.availability != nil {
|
||||
return false
|
||||
if !disallowedGifts.contains(.unique) && gift.upgradeStars != nil {
|
||||
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -371,7 +371,7 @@ final class GiftSetupScreenComponent: Component {
|
||||
} else {
|
||||
fatalError()
|
||||
}
|
||||
case let .starGift(starGift):
|
||||
case let .starGift(starGift, _):
|
||||
finalPrice = starGift.price
|
||||
if self.includeUpgrade, let upgradeStars = starGift.upgradeStars {
|
||||
finalPrice += upgradeStars
|
||||
@ -390,8 +390,13 @@ final class GiftSetupScreenComponent: Component {
|
||||
let completion = component.completion
|
||||
|
||||
let signal = BotCheckoutController.InputData.fetch(context: component.context, source: source)
|
||||
|> `catch` { _ -> Signal<BotCheckoutController.InputData, SendBotPaymentFormError> in
|
||||
return .fail(.generic)
|
||||
|> `catch` { error -> Signal<BotCheckoutController.InputData, SendBotPaymentFormError> in
|
||||
switch error {
|
||||
case .disallowedStarGifts:
|
||||
return .fail(.disallowedStarGift)
|
||||
default:
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
|> mapToSignal { inputData -> Signal<SendBotPaymentResult, SendBotPaymentFormError> in
|
||||
return component.context.engine.payments.sendStarsPaymentForm(formId: inputData.form.id, source: source)
|
||||
@ -403,7 +408,7 @@ final class GiftSetupScreenComponent: Component {
|
||||
return
|
||||
}
|
||||
|
||||
if peerId.namespace == Namespaces.Peer.CloudChannel, case let .starGift(starGift) = component.subject {
|
||||
if peerId.namespace == Namespaces.Peer.CloudChannel, case let .starGift(starGift, _) = component.subject {
|
||||
var controllers = navigationController.viewControllers
|
||||
controllers = controllers.filter { !($0 is GiftSetupScreen) && !($0 is GiftOptionsScreenProtocol) }
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
@ -555,6 +560,10 @@ final class GiftSetupScreenComponent: Component {
|
||||
self.hideName = true
|
||||
}
|
||||
|
||||
if case let .starGift(gift, true) = component.subject, gift.upgradeStars != nil {
|
||||
self.includeUpgrade = true
|
||||
}
|
||||
|
||||
let _ = (component.context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: component.peerId),
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: component.context.account.peerId),
|
||||
@ -684,7 +693,7 @@ final class GiftSetupScreenComponent: Component {
|
||||
self.options = options
|
||||
})
|
||||
|
||||
if case let .starGift(gift) = component.subject {
|
||||
if case let .starGift(gift, _) = component.subject {
|
||||
if let _ = gift.upgradeStars {
|
||||
self.previewPromise.set(
|
||||
component.context.engine.payments.starGiftUpgradePreview(giftId: gift.id)
|
||||
@ -742,7 +751,7 @@ final class GiftSetupScreenComponent: Component {
|
||||
contentHeight += environment.navigationHeight
|
||||
contentHeight += 26.0
|
||||
|
||||
if case let .starGift(starGift) = component.subject, let availability = starGift.availability {
|
||||
if case let .starGift(starGift, _) = component.subject, let availability = starGift.availability {
|
||||
let remains: Int32 = availability.remains
|
||||
let total: Int32 = availability.total
|
||||
let position = CGFloat(remains) / CGFloat(total)
|
||||
@ -909,7 +918,7 @@ final class GiftSetupScreenComponent: Component {
|
||||
let (currency, amount) = product.storeProduct?.priceCurrencyAndAmount ?? ("USD", 1)
|
||||
subject = .premium(months: product.months, amount: amount, currency: currency)
|
||||
}
|
||||
case let .starGift(gift):
|
||||
case let .starGift(gift, _):
|
||||
subject = .starGift(gift: gift)
|
||||
upgradeStars = gift.upgradeStars
|
||||
}
|
||||
@ -1061,13 +1070,17 @@ final class GiftSetupScreenComponent: Component {
|
||||
contentHeight += starsSectionSize.height
|
||||
contentHeight += sectionSpacing
|
||||
}
|
||||
case let .starGift(gift):
|
||||
case let .starGift(gift, forceUnique):
|
||||
if let upgradeStars = gift.upgradeStars, component.peerId != component.context.account.peerId {
|
||||
let upgradeFooterRawString: String
|
||||
if isChannelGift {
|
||||
upgradeFooterRawString = environment.strings.Gift_SendChannel_Upgrade_Info(peerName).string
|
||||
} else {
|
||||
upgradeFooterRawString = environment.strings.Gift_Send_Upgrade_Info(peerName).string
|
||||
if forceUnique {
|
||||
upgradeFooterRawString = environment.strings.Gift_Send_Upgrade_ForcedInfo(peerName).string
|
||||
} else {
|
||||
upgradeFooterRawString = environment.strings.Gift_Send_Upgrade_Info(peerName).string
|
||||
}
|
||||
}
|
||||
let parsedString = parseMarkdownIntoAttributedString(upgradeFooterRawString, attributes: footerAttributes)
|
||||
|
||||
@ -1136,8 +1149,8 @@ final class GiftSetupScreenComponent: Component {
|
||||
)
|
||||
)),
|
||||
], alignment: .left, spacing: 2.0)),
|
||||
accessory: .toggle(ListActionItemComponent.Toggle(style: .regular, isOn: self.includeUpgrade, action: { [weak self] _ in
|
||||
guard let self else {
|
||||
accessory: .toggle(ListActionItemComponent.Toggle(style: .regular, isOn: self.includeUpgrade, isEnabled: !forceUnique, action: { [weak self] _ in
|
||||
guard let self, !forceUnique else {
|
||||
return
|
||||
}
|
||||
self.includeUpgrade = !self.includeUpgrade
|
||||
@ -1263,7 +1276,7 @@ final class GiftSetupScreenComponent: Component {
|
||||
let amountString = product.price
|
||||
buttonString = "\(environment.strings.Gift_Send_Send) \(amountString)"
|
||||
}
|
||||
case let .starGift(starGift):
|
||||
case let .starGift(starGift, _):
|
||||
var finalPrice: Int64 = starGift.price
|
||||
if self.includeUpgrade, let upgradePrice = starGift.upgradeStars {
|
||||
finalPrice += upgradePrice
|
||||
@ -1685,7 +1698,7 @@ final class GiftSetupScreenComponent: Component {
|
||||
public final class GiftSetupScreen: ViewControllerComponentContainer {
|
||||
public enum Subject: Equatable {
|
||||
case premium(PremiumGiftProduct)
|
||||
case starGift(StarGift.Gift)
|
||||
case starGift(StarGift.Gift, Bool)
|
||||
}
|
||||
|
||||
private let context: AccountContext
|
||||
|
||||
@ -141,3 +141,24 @@ private func generateCloseButtonImage() -> UIImage? {
|
||||
context.strokePath()
|
||||
})?.withRenderingMode(.alwaysTemplate)
|
||||
}
|
||||
|
||||
func generateCloseButtonImage(backgroundColor: UIColor, foregroundColor: UIColor) -> UIImage? {
|
||||
return generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
context.setFillColor(backgroundColor.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
context.setLineWidth(2.0)
|
||||
context.setLineCap(.round)
|
||||
context.setStrokeColor(foregroundColor.cgColor)
|
||||
|
||||
context.move(to: CGPoint(x: 10.0, y: 10.0))
|
||||
context.addLine(to: CGPoint(x: 20.0, y: 20.0))
|
||||
context.strokePath()
|
||||
|
||||
context.move(to: CGPoint(x: 20.0, y: 10.0))
|
||||
context.addLine(to: CGPoint(x: 10.0, y: 20.0))
|
||||
context.strokePath()
|
||||
})
|
||||
}
|
||||
|
||||
@ -0,0 +1,381 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import ComponentFlow
|
||||
import SwiftSignalKit
|
||||
import TelegramCore
|
||||
import Markdown
|
||||
import TextFormat
|
||||
import TelegramPresentationData
|
||||
import ViewControllerComponent
|
||||
import SheetComponent
|
||||
import BundleIconComponent
|
||||
import BalancedTextComponent
|
||||
import MultilineTextComponent
|
||||
import ButtonComponent
|
||||
import PlainButtonComponent
|
||||
import GiftItemComponent
|
||||
import AccountContext
|
||||
|
||||
private final class SheetContent: CombinedComponent {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
|
||||
let context: AccountContext
|
||||
let gifts: [ProfileGiftsContext.State.StarGift]
|
||||
let completion: (StarGiftReference) -> Void
|
||||
let dismiss: () -> Void
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
gifts: [ProfileGiftsContext.State.StarGift],
|
||||
completion: @escaping (StarGiftReference) -> Void,
|
||||
dismiss: @escaping () -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.gifts = gifts
|
||||
self.completion = completion
|
||||
self.dismiss = dismiss
|
||||
}
|
||||
|
||||
static func ==(lhs: SheetContent, rhs: SheetContent) -> Bool {
|
||||
if lhs.context !== rhs.context {
|
||||
return false
|
||||
}
|
||||
if lhs.gifts != rhs.gifts {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
final class State: ComponentState {
|
||||
var selectedGift: StarGiftReference?
|
||||
}
|
||||
|
||||
func makeState() -> State {
|
||||
return State()
|
||||
}
|
||||
|
||||
static var body: Body {
|
||||
let closeButton = Child(Button.self)
|
||||
|
||||
let title = Child(BalancedTextComponent.self)
|
||||
let text = Child(BalancedTextComponent.self)
|
||||
let gifts = ChildMap(environment: Empty.self, keyedBy: AnyHashable.self)
|
||||
let button = Child(ButtonComponent.self)
|
||||
|
||||
return { context in
|
||||
let environment = context.environment[EnvironmentType.self]
|
||||
let component = context.component
|
||||
let state = context.state
|
||||
|
||||
let theme = environment.theme
|
||||
let strings = environment.strings
|
||||
|
||||
let sideInset: CGFloat = 16.0 + environment.safeInsets.left
|
||||
let textSideInset: CGFloat = 32.0 + environment.safeInsets.left
|
||||
|
||||
let titleFont = Font.semibold(17.0)
|
||||
let subtitleFont = Font.regular(12.0)
|
||||
let textColor = theme.actionSheet.primaryTextColor
|
||||
let secondaryTextColor = theme.actionSheet.secondaryTextColor
|
||||
|
||||
var contentSize = CGSize(width: context.availableSize.width, height: 10.0)
|
||||
|
||||
let closeButton = closeButton.update(
|
||||
component: Button(
|
||||
content: AnyComponent(Text(text: strings.Common_Cancel, font: Font.regular(17.0), color: theme.actionSheet.controlAccentColor)),
|
||||
action: { [weak component] in
|
||||
component?.dismiss()
|
||||
}
|
||||
),
|
||||
availableSize: CGSize(width: 100.0, height: 30.0),
|
||||
transition: .immediate
|
||||
)
|
||||
context.add(closeButton
|
||||
.position(CGPoint(x: environment.safeInsets.left + 16.0 + closeButton.size.width / 2.0, y: 28.0))
|
||||
)
|
||||
|
||||
let title = title.update(
|
||||
component: BalancedTextComponent(
|
||||
text: .plain(NSAttributedString(string: "Too Many Pinned Gifts", font: titleFont, textColor: textColor)),
|
||||
horizontalAlignment: .center,
|
||||
maximumNumberOfLines: 1,
|
||||
lineSpacing: 0.1
|
||||
),
|
||||
availableSize: CGSize(width: context.availableSize.width - textSideInset * 2.0, height: context.availableSize.height),
|
||||
transition: .immediate
|
||||
)
|
||||
context.add(title
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + title.size.height / 2.0))
|
||||
)
|
||||
contentSize.height += title.size.height
|
||||
|
||||
let text = text.update(
|
||||
component: BalancedTextComponent(
|
||||
text: .plain(NSAttributedString(string: "Select a gift to unpin below:", font: subtitleFont, textColor: secondaryTextColor)),
|
||||
horizontalAlignment: .center,
|
||||
maximumNumberOfLines: 1,
|
||||
lineSpacing: 0.2
|
||||
),
|
||||
availableSize: CGSize(width: context.availableSize.width - textSideInset * 2.0, height: context.availableSize.height),
|
||||
transition: .immediate
|
||||
)
|
||||
context.add(text
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + text.size.height / 2.0))
|
||||
)
|
||||
contentSize.height += text.size.height
|
||||
contentSize.height += 17.0
|
||||
|
||||
let itemsSideInset = environment.safeInsets.left + 16.0
|
||||
let spacing: CGFloat = 10.0
|
||||
let itemsInRow = 3
|
||||
let width = (context.availableSize.width - itemsSideInset * 2.0 - spacing * CGFloat(itemsInRow - 1)) / CGFloat(itemsInRow)
|
||||
|
||||
var updatedGifts: [_UpdatedChildComponent] = []
|
||||
var index = 0
|
||||
var nextOriginX = itemsSideInset
|
||||
for gift in component.gifts {
|
||||
guard case let .unique(uniqueGift) = gift.gift else {
|
||||
continue
|
||||
}
|
||||
var ribbonColor: GiftItemComponent.Ribbon.Color = .blue
|
||||
for attribute in uniqueGift.attributes {
|
||||
if case let .backdrop(_, innerColor, outerColor, _, _, _) = attribute {
|
||||
ribbonColor = .custom(outerColor, innerColor)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
updatedGifts.append(
|
||||
gifts[index].update(
|
||||
component: AnyComponent(
|
||||
PlainButtonComponent(
|
||||
content: AnyComponent(
|
||||
GiftItemComponent(
|
||||
context: component.context,
|
||||
theme: theme,
|
||||
strings: strings,
|
||||
subject: .uniqueGift(gift: uniqueGift),
|
||||
ribbon: GiftItemComponent.Ribbon(text: "#\(uniqueGift.number)", font: .monospaced, color: ribbonColor),
|
||||
isSelected: state.selectedGift == gift.reference,
|
||||
mode: .grid
|
||||
)
|
||||
),
|
||||
effectAlignment: .center,
|
||||
action: { [weak state] in
|
||||
guard let state else {
|
||||
return
|
||||
}
|
||||
state.selectedGift = gift.reference
|
||||
state.updated(transition: .spring(duration: 0.3))
|
||||
},
|
||||
animateAlpha: false
|
||||
)
|
||||
),
|
||||
availableSize: CGSize(width: width, height: width),
|
||||
transition: context.transition
|
||||
)
|
||||
)
|
||||
context.add(updatedGifts[index]
|
||||
.position(CGPoint(x: nextOriginX + updatedGifts[index].size.width / 2.0, y: contentSize.height + updatedGifts[index].size.height / 2.0))
|
||||
)
|
||||
|
||||
nextOriginX += updatedGifts[index].size.width + spacing
|
||||
if nextOriginX > context.availableSize.width - itemsSideInset {
|
||||
contentSize.height += updatedGifts[index].size.height + spacing
|
||||
nextOriginX = itemsSideInset
|
||||
}
|
||||
|
||||
index += 1
|
||||
}
|
||||
contentSize.height += 14.0
|
||||
|
||||
let button = button.update(
|
||||
component: ButtonComponent(
|
||||
background: ButtonComponent.Background(
|
||||
color: theme.list.itemCheckColors.fillColor,
|
||||
foreground: theme.list.itemCheckColors.foregroundColor,
|
||||
pressedColor: theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9)
|
||||
),
|
||||
content: AnyComponentWithIdentity(
|
||||
id: AnyHashable("unpin"),
|
||||
component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: "Unpin", font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center))))
|
||||
),
|
||||
isEnabled: state.selectedGift != nil,
|
||||
displaysProgress: false,
|
||||
action: { [weak state] in
|
||||
guard let state else {
|
||||
return
|
||||
}
|
||||
if let selectedGift = state.selectedGift {
|
||||
component.completion(selectedGift)
|
||||
component.dismiss()
|
||||
}
|
||||
}
|
||||
),
|
||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 50.0),
|
||||
transition: context.transition
|
||||
)
|
||||
context.add(button
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + button.size.height / 2.0))
|
||||
.cornerRadius(10.0)
|
||||
)
|
||||
contentSize.height += button.size.height
|
||||
contentSize.height += 7.0
|
||||
|
||||
let effectiveBottomInset: CGFloat = environment.metrics.isTablet ? 0.0 : environment.safeInsets.bottom
|
||||
contentSize.height += 5.0 + effectiveBottomInset
|
||||
|
||||
return contentSize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class SheetContainerComponent: CombinedComponent {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
|
||||
let context: AccountContext
|
||||
let gifts: [ProfileGiftsContext.State.StarGift]
|
||||
let completion: (StarGiftReference) -> Void
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
gifts: [ProfileGiftsContext.State.StarGift],
|
||||
completion: @escaping (StarGiftReference) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.gifts = gifts
|
||||
self.completion = completion
|
||||
}
|
||||
|
||||
static func ==(lhs: SheetContainerComponent, rhs: SheetContainerComponent) -> Bool {
|
||||
if lhs.context !== rhs.context {
|
||||
return false
|
||||
}
|
||||
if lhs.gifts != rhs.gifts {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
static var body: Body {
|
||||
let sheet = Child(SheetComponent<EnvironmentType>.self)
|
||||
let animateOut = StoredActionSlot(Action<Void>.self)
|
||||
|
||||
let sheetExternalState = SheetComponent<EnvironmentType>.ExternalState()
|
||||
|
||||
return { context in
|
||||
let environment = context.environment[EnvironmentType.self]
|
||||
|
||||
let controller = environment.controller
|
||||
|
||||
let sheet = sheet.update(
|
||||
component: SheetComponent<EnvironmentType>(
|
||||
content: AnyComponent<EnvironmentType>(SheetContent(
|
||||
context: context.component.context,
|
||||
gifts: context.component.gifts,
|
||||
completion: context.component.completion,
|
||||
dismiss: {
|
||||
animateOut.invoke(Action { _ in
|
||||
if let controller = controller() {
|
||||
controller.dismiss(completion: nil)
|
||||
}
|
||||
})
|
||||
}
|
||||
)),
|
||||
backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor),
|
||||
followContentSizeChanges: true,
|
||||
externalState: sheetExternalState,
|
||||
animateOut: animateOut
|
||||
),
|
||||
environment: {
|
||||
environment
|
||||
SheetComponentEnvironment(
|
||||
isDisplaying: environment.value.isVisible,
|
||||
isCentered: environment.metrics.widthClass == .regular,
|
||||
hasInputHeight: !environment.inputHeight.isZero,
|
||||
regularMetricsSize: CGSize(width: 430.0, height: 900.0),
|
||||
dismiss: { animated in
|
||||
if animated {
|
||||
animateOut.invoke(Action { _ in
|
||||
if let controller = controller() {
|
||||
controller.dismiss(completion: nil)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if let controller = controller() {
|
||||
controller.dismiss(completion: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
availableSize: context.availableSize,
|
||||
transition: context.transition
|
||||
)
|
||||
|
||||
context.add(sheet
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height / 2.0))
|
||||
)
|
||||
|
||||
if let controller = controller(), !controller.automaticallyControlPresentationContextLayout {
|
||||
let layout = ContainerViewLayout(
|
||||
size: context.availableSize,
|
||||
metrics: environment.metrics,
|
||||
deviceMetrics: environment.deviceMetrics,
|
||||
intrinsicInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: max(environment.safeInsets.bottom, sheetExternalState.contentHeight), right: 0.0),
|
||||
safeInsets: UIEdgeInsets(top: 0.0, left: environment.safeInsets.left, bottom: 0.0, right: environment.safeInsets.right),
|
||||
additionalInsets: .zero,
|
||||
statusBarHeight: environment.statusBarHeight,
|
||||
inputHeight: nil,
|
||||
inputHeightIsInteractivellyChanging: false,
|
||||
inVoiceOver: false
|
||||
)
|
||||
controller.presentationContext.containerLayoutUpdated(layout, transition: context.transition.containedViewLayoutTransition)
|
||||
}
|
||||
|
||||
return context.availableSize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class GiftUnpinScreen: ViewControllerComponentContainer {
|
||||
private let context: AccountContext
|
||||
private let gifts: [ProfileGiftsContext.State.StarGift]
|
||||
private let completion: (StarGiftReference) -> Void
|
||||
|
||||
public init(
|
||||
context: AccountContext,
|
||||
gifts: [ProfileGiftsContext.State.StarGift],
|
||||
completion: @escaping (StarGiftReference) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.gifts = gifts
|
||||
self.completion = completion
|
||||
|
||||
super.init(
|
||||
context: context,
|
||||
component: SheetContainerComponent(
|
||||
context: context,
|
||||
gifts: gifts,
|
||||
completion: completion
|
||||
),
|
||||
navigationBarAppearance: .none,
|
||||
statusBarStyle: .ignore,
|
||||
theme: .default
|
||||
)
|
||||
|
||||
self.navigationPresentation = .flatModal
|
||||
}
|
||||
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
public func dismissAnimated() {
|
||||
if let view = self.node.hostView.findTaggedView(tag: SheetComponent<ViewControllerComponentContainer.Environment>.View.Tag()) as? SheetComponent<ViewControllerComponentContainer.Environment>.View {
|
||||
view.dismissAnimated()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3007,12 +3007,6 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
self.subject = .profileGift(peerId, gift.withPinnedToTop(false))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var maxPinnedCount: Int = 6
|
||||
if let value = context.currentAppConfiguration.with({ $0 }).data?["stargifts_pinned_to_top_limit"] as? Double {
|
||||
maxPinnedCount = Int(value)
|
||||
}
|
||||
self.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: strings.PeerInfo_Gifts_ToastPinLimit_Text(Int32(maxPinnedCount)), timeout: nil, customUndoText: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
||||
}
|
||||
})
|
||||
})))
|
||||
|
||||
@ -18,12 +18,14 @@ public final class ListActionItemComponent: Component {
|
||||
public var style: ToggleStyle
|
||||
public var isOn: Bool
|
||||
public var isInteractive: Bool
|
||||
public var isEnabled: Bool
|
||||
public var action: ((Bool) -> Void)?
|
||||
|
||||
public init(style: ToggleStyle, isOn: Bool, isInteractive: Bool = true, action: ((Bool) -> Void)? = nil) {
|
||||
public init(style: ToggleStyle, isOn: Bool, isInteractive: Bool = true, isEnabled: Bool = true, action: ((Bool) -> Void)? = nil) {
|
||||
self.style = style
|
||||
self.isOn = isOn
|
||||
self.isInteractive = isInteractive
|
||||
self.isEnabled = isEnabled
|
||||
self.action = action
|
||||
}
|
||||
|
||||
@ -37,6 +39,9 @@ public final class ListActionItemComponent: Component {
|
||||
if lhs.isInteractive != rhs.isInteractive {
|
||||
return false
|
||||
}
|
||||
if lhs.isEnabled != rhs.isEnabled {
|
||||
return false
|
||||
}
|
||||
if (lhs.action == nil) != (rhs.action == nil) {
|
||||
return false
|
||||
}
|
||||
@ -648,7 +653,9 @@ public final class ListActionItemComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
switchNode.isUserInteractionEnabled = toggle.isInteractive
|
||||
switchNode.isUserInteractionEnabled = toggle.isInteractive && toggle.isEnabled
|
||||
switchNode.alpha = toggle.isEnabled ? 1.0 : 0.3
|
||||
switchNode.layer.allowsGroupOpacity = !toggle.isEnabled
|
||||
|
||||
if updateSwitchTheme {
|
||||
switchNode.frameColor = component.theme.list.itemSwitchColors.frameColor
|
||||
|
||||
@ -187,7 +187,7 @@ public final class LoadingOverlayNode: ASDisplayNode {
|
||||
}, editPeer: { _ in
|
||||
}, openWebApp: { _ in
|
||||
}, openPhotoSetup: {
|
||||
}, openAdInfo: { _ in
|
||||
}, openAdInfo: { _, _ in
|
||||
}, openAccountFreezeInfo: {
|
||||
})
|
||||
|
||||
@ -548,7 +548,7 @@ private final class PeerInfoScreenPersonalChannelItemNode: PeerInfoScreenItemNod
|
||||
},
|
||||
openPhotoSetup: {
|
||||
},
|
||||
openAdInfo: { _ in
|
||||
openAdInfo: { _, _ in
|
||||
},
|
||||
openAccountFreezeInfo: {
|
||||
}
|
||||
|
||||
@ -540,14 +540,18 @@ private final class PeerInfoPendingPane {
|
||||
switch key {
|
||||
case .gifts:
|
||||
var canManage = false
|
||||
var canGift = true
|
||||
if let peer = data.peer {
|
||||
if let cachedUserData = data.cachedData as? CachedUserData, cachedUserData.disallowedGifts == .All {
|
||||
canGift = false
|
||||
}
|
||||
if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
if channel.hasPermission(.sendSomething) {
|
||||
canManage = true
|
||||
}
|
||||
}
|
||||
}
|
||||
paneNode = PeerInfoGiftsPaneNode(context: context, peerId: peerId, chatControllerInteraction: chatControllerInteraction, profileGifts: data.profileGiftsContext!, canManage: canManage)
|
||||
paneNode = PeerInfoGiftsPaneNode(context: context, peerId: peerId, chatControllerInteraction: chatControllerInteraction, profileGifts: data.profileGiftsContext!, canManage: canManage, canGift: canGift)
|
||||
case .stories, .storyArchive, .botPreview:
|
||||
var canManage = false
|
||||
if let peer = data.peer {
|
||||
|
||||
@ -6435,15 +6435,18 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
|
||||
if strongSelf.peerId.namespace == Namespaces.Peer.CloudUser, !user.isDeleted && user.botInfo == nil && !user.flags.contains(.isSupport) {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Profile_SendGift, icon: { theme in
|
||||
generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Gift"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
if let self {
|
||||
self.openPremiumGift()
|
||||
}
|
||||
})))
|
||||
if let cachedData = data.cachedData as? CachedUserData, cachedData.disallowedGifts == .All {
|
||||
} else {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Profile_SendGift, icon: { theme in
|
||||
generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Gift"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
if let self {
|
||||
self.openPremiumGift()
|
||||
}
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
if let cachedData = data.cachedData as? CachedUserData, cachedData.flags.contains(.translationHidden) {
|
||||
@ -14360,7 +14363,7 @@ private final class AccountPeerContextItemNode: ASDisplayNode, ContextMenuCustom
|
||||
action: nil
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 28.0, height: 28.0)
|
||||
containerSize: CGSize(width: 24.0, height: 24.0)
|
||||
)
|
||||
if let view = self.emojiStatusView.view {
|
||||
if view.superview == nil {
|
||||
|
||||
@ -33,6 +33,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
private let peerId: PeerId
|
||||
private let profileGifts: ProfileGiftsContext
|
||||
private let canManage: Bool
|
||||
private let canGift: Bool
|
||||
|
||||
private var dataDisposable: Disposable?
|
||||
|
||||
@ -101,12 +102,13 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
|
||||
private let maxPinnedCount: Int
|
||||
|
||||
public init(context: AccountContext, peerId: PeerId, chatControllerInteraction: ChatControllerInteraction, profileGifts: ProfileGiftsContext, canManage: Bool) {
|
||||
public init(context: AccountContext, peerId: PeerId, chatControllerInteraction: ChatControllerInteraction, profileGifts: ProfileGiftsContext, canManage: Bool, canGift: Bool) {
|
||||
self.context = context
|
||||
self.peerId = peerId
|
||||
self.chatControllerInteraction = chatControllerInteraction
|
||||
self.profileGifts = profileGifts
|
||||
self.canManage = canManage
|
||||
self.canGift = canGift
|
||||
|
||||
self.backgroundNode = ASDisplayNode()
|
||||
self.scrollNode = ASScrollNode()
|
||||
@ -434,6 +436,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
|
||||
let ribbonText: String?
|
||||
var ribbonColor: GiftItemComponent.Ribbon.Color = .blue
|
||||
var ribbonFont: GiftItemComponent.Ribbon.Font = .generic
|
||||
switch product.gift {
|
||||
case let .generic(gift):
|
||||
if let availability = gift.availability {
|
||||
@ -442,7 +445,8 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
ribbonText = nil
|
||||
}
|
||||
case let .unique(gift):
|
||||
ribbonText = params.presentationData.strings.PeerInfo_Gifts_OneOf(compactNumericCountString(Int(gift.availability.issued), decimalSeparator: params.presentationData.dateTimeFormat.decimalSeparator)).string
|
||||
ribbonFont = .monospaced
|
||||
ribbonText = "#\(gift.number)"
|
||||
for attribute in gift.attributes {
|
||||
if case let .backdrop(_, innerColor, outerColor, _, _, _) = attribute {
|
||||
ribbonColor = .custom(outerColor, innerColor)
|
||||
@ -471,7 +475,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
strings: params.presentationData.strings,
|
||||
peer: peer,
|
||||
subject: subject,
|
||||
ribbon: ribbonText.flatMap { GiftItemComponent.Ribbon(text: $0, color: ribbonColor) },
|
||||
ribbon: ribbonText.flatMap { GiftItemComponent.Ribbon(text: $0, font: ribbonFont, color: ribbonColor) },
|
||||
isHidden: !product.savedToProfile,
|
||||
isPinned: product.pinnedToTop,
|
||||
isEditing: self.isReordering,
|
||||
@ -510,6 +514,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var dismissImpl: (() -> Void)?
|
||||
let controller = GiftViewScreen(
|
||||
context: self.context,
|
||||
subject: .profileGift(self.peerId, product),
|
||||
@ -542,15 +547,58 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
return false
|
||||
}
|
||||
if pinnedToTop && self.pinnedReferences.count >= self.maxPinnedCount {
|
||||
if let gifts = self.profileGifts.currentState?.gifts.filter({ $0.pinnedToTop }) {
|
||||
let controller = GiftUnpinScreen(
|
||||
context: context,
|
||||
gifts: gifts,
|
||||
completion: { [weak self] unpinnedReference in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
dismissImpl?()
|
||||
|
||||
var replacingTitle = ""
|
||||
for gift in gifts {
|
||||
if gift.reference == unpinnedReference, case let .unique(uniqueGift) = gift.gift {
|
||||
replacingTitle = "\(uniqueGift.title) #\(presentationStringsFormattedNumber(uniqueGift.number, params.presentationData.dateTimeFormat.groupingSeparator))"
|
||||
}
|
||||
}
|
||||
|
||||
var updatedPinnedGifts = self.pinnedReferences
|
||||
if let index = updatedPinnedGifts.firstIndex(of: unpinnedReference), let reference = product.reference {
|
||||
updatedPinnedGifts[index] = reference
|
||||
}
|
||||
self.profileGifts.updatePinnedToTopStarGifts(references: updatedPinnedGifts)
|
||||
|
||||
var title = ""
|
||||
if case let .unique(uniqueGift) = product.gift {
|
||||
title = "\(uniqueGift.title) #\(presentationStringsFormattedNumber(uniqueGift.number, params.presentationData.dateTimeFormat.groupingSeparator))"
|
||||
}
|
||||
|
||||
let _ = self.scrollToTop()
|
||||
Queue.mainQueue().after(0.35) {
|
||||
let toastTitle = params.presentationData.strings.PeerInfo_Gifts_ToastPinned_TitleNew(title).string
|
||||
let toastText = params.presentationData.strings.PeerInfo_Gifts_ToastPinned_ReplacingText(replacingTitle).string
|
||||
self.parentController?.present(UndoOverlayController(presentationData: params.presentationData, content: .universal(animation: "anim_toastpin", scale: 0.06, colors: [:], title: toastTitle, text: toastText, customUndoText: nil, timeout: 5), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
}
|
||||
}
|
||||
)
|
||||
self.parentController?.push(controller)
|
||||
}
|
||||
return false
|
||||
}
|
||||
if let reference = product.reference {
|
||||
self.profileGifts.updateStarGiftPinnedToTop(reference: reference, pinnedToTop: pinnedToTop)
|
||||
|
||||
var title = ""
|
||||
if case let .unique(uniqueGift) = product.gift {
|
||||
title = "\(uniqueGift.title) #\(presentationStringsFormattedNumber(uniqueGift.number, params.presentationData.dateTimeFormat.groupingSeparator))"
|
||||
}
|
||||
|
||||
if pinnedToTop {
|
||||
let _ = self.scrollToTop()
|
||||
Queue.mainQueue().after(0.35) {
|
||||
let toastTitle = params.presentationData.strings.PeerInfo_Gifts_ToastPinned_Title
|
||||
let toastTitle = params.presentationData.strings.PeerInfo_Gifts_ToastPinned_TitleNew(title).string
|
||||
let toastText = params.presentationData.strings.PeerInfo_Gifts_ToastPinned_Text
|
||||
self.parentController?.present(UndoOverlayController(presentationData: params.presentationData, content: .universal(animation: "anim_toastpin", scale: 0.06, colors: [:], title: toastTitle, text: toastText, customUndoText: nil, timeout: 5), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
}
|
||||
@ -568,6 +616,9 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
}
|
||||
}
|
||||
)
|
||||
dismissImpl = { [weak controller] in
|
||||
controller?.dismissAnimated()
|
||||
}
|
||||
self.parentController?.push(controller)
|
||||
}
|
||||
},
|
||||
@ -657,7 +708,10 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
let panelSeparator: ASDisplayNode
|
||||
let panelButton: SolidRoundedButtonNode
|
||||
|
||||
let panelAlpha = params.expandProgress
|
||||
var panelAlpha = params.expandProgress
|
||||
if !self.canGift {
|
||||
panelAlpha = 0.0
|
||||
}
|
||||
|
||||
if let current = self.panelBackground {
|
||||
panelBackground = current
|
||||
@ -1021,7 +1075,11 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
toastTitle = nil
|
||||
toastText = strings.PeerInfo_Gifts_ToastUnpinned_Text
|
||||
} else {
|
||||
toastTitle = strings.PeerInfo_Gifts_ToastPinned_Title
|
||||
var title = ""
|
||||
if case let .unique(uniqueGift) = gift.gift {
|
||||
title = "\(uniqueGift.title) #\(presentationStringsFormattedNumber(uniqueGift.number, presentationData.dateTimeFormat.groupingSeparator))"
|
||||
}
|
||||
toastTitle = strings.PeerInfo_Gifts_ToastPinned_TitleNew(title).string
|
||||
toastText = strings.PeerInfo_Gifts_ToastPinned_Text
|
||||
}
|
||||
self.parentController?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: !pinnedToTop ? "anim_toastunpin" : "anim_toastpin", scale: 0.06, colors: [:], title: toastTitle, text: toastText, customUndoText: nil, timeout: 5), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
|
||||
@ -111,7 +111,7 @@ private final class SheetContent: CombinedComponent {
|
||||
|
||||
let title = title.update(
|
||||
component: BalancedTextComponent(
|
||||
text: .plain(NSAttributedString(string: "Your Account is Frozen", font: titleFont, textColor: textColor)),
|
||||
text: .plain(NSAttributedString(string: strings.FrozenAccount_Title, font: titleFont, textColor: textColor)),
|
||||
horizontalAlignment: .center,
|
||||
maximumNumberOfLines: 0,
|
||||
lineSpacing: 0.1
|
||||
@ -125,15 +125,14 @@ private final class SheetContent: CombinedComponent {
|
||||
contentSize.height += title.size.height
|
||||
contentSize.height += spacing - 2.0
|
||||
|
||||
//TODO:localize
|
||||
var items: [AnyComponentWithIdentity<Empty>] = []
|
||||
items.append(
|
||||
AnyComponentWithIdentity(
|
||||
id: "ads",
|
||||
id: "violation",
|
||||
component: AnyComponent(ParagraphComponent(
|
||||
title: "Violation of Terms",
|
||||
title: strings.FrozenAccount_Violation_Title,
|
||||
titleColor: textColor,
|
||||
text: "Your account was frozen for breaking Telegram's Terms and Conditions.",
|
||||
text: strings.FrozenAccount_Violation_Text,
|
||||
textColor: secondaryTextColor,
|
||||
iconName: "Account Freeze/Violation",
|
||||
iconColor: linkColor
|
||||
@ -142,11 +141,11 @@ private final class SheetContent: CombinedComponent {
|
||||
)
|
||||
items.append(
|
||||
AnyComponentWithIdentity(
|
||||
id: "split",
|
||||
id: "readOnly",
|
||||
component: AnyComponent(ParagraphComponent(
|
||||
title: "Read-Only Mode",
|
||||
title: strings.FrozenAccount_ReadOnly_Title,
|
||||
titleColor: textColor,
|
||||
text: "You can access your account but can't send messages or take actions.",
|
||||
text: strings.FrozenAccount_ReadOnly_Text,
|
||||
textColor: secondaryTextColor,
|
||||
iconName: "Ads/Privacy",
|
||||
iconColor: linkColor
|
||||
@ -156,19 +155,17 @@ private final class SheetContent: CombinedComponent {
|
||||
let dateString = stringForFullDate(timestamp: component.configuration.freezeUntilDate ?? 0, strings: strings, dateTimeFormat: environment.dateTimeFormat)
|
||||
items.append(
|
||||
AnyComponentWithIdentity(
|
||||
id: "withdrawal",
|
||||
id: "appeal",
|
||||
component: AnyComponent(ParagraphComponent(
|
||||
title: "Appeal Before Deactivation",
|
||||
title: strings.FrozenAccount_Appeal_Title,
|
||||
titleColor: textColor,
|
||||
text: "Appeal via [@SpamBot]() before \(dateString), or your account will be deleted.",
|
||||
text: strings.FrozenAccount_Appeal_Text(dateString).string,
|
||||
textColor: secondaryTextColor,
|
||||
iconName: "Account Freeze/Appeal",
|
||||
iconColor: linkColor,
|
||||
action: {
|
||||
component.submitAppeal()
|
||||
component.dismiss()
|
||||
Queue.mainQueue().after(0.5) {
|
||||
component.submitAppeal()
|
||||
}
|
||||
}
|
||||
))
|
||||
)
|
||||
@ -185,7 +182,7 @@ private final class SheetContent: CombinedComponent {
|
||||
contentSize.height += list.size.height
|
||||
contentSize.height += spacing + 2.0
|
||||
|
||||
let buttonAttributedString = NSMutableAttributedString(string: "Submit an Appeal", font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
|
||||
let buttonAttributedString = NSMutableAttributedString(string: strings.FrozenAccount_SubmitAppeal, font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
|
||||
let actionButton = actionButton.update(
|
||||
component: ButtonComponent(
|
||||
background: ButtonComponent.Background(
|
||||
@ -201,10 +198,8 @@ private final class SheetContent: CombinedComponent {
|
||||
isEnabled: true,
|
||||
displaysProgress: false,
|
||||
action: {
|
||||
component.submitAppeal()
|
||||
component.dismiss()
|
||||
Queue.mainQueue().after(0.5) {
|
||||
component.submitAppeal()
|
||||
}
|
||||
}
|
||||
),
|
||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 50.0),
|
||||
@ -217,7 +212,7 @@ private final class SheetContent: CombinedComponent {
|
||||
contentSize.height += actionButton.size.height
|
||||
contentSize.height += 8.0
|
||||
|
||||
let closeAttributedString = NSMutableAttributedString(string: "Understood", font: Font.regular(17.0), textColor: environment.theme.list.itemCheckColors.fillColor, paragraphAlignment: .center)
|
||||
let closeAttributedString = NSMutableAttributedString(string: strings.FrozenAccount_Understood, font: Font.regular(17.0), textColor: environment.theme.list.itemCheckColors.fillColor, paragraphAlignment: .center)
|
||||
let closeButton = closeButton.update(
|
||||
component: ButtonComponent(
|
||||
background: ButtonComponent.Background(
|
||||
@ -390,10 +385,12 @@ public final class AccountFreezeInfoScreen: ViewControllerComponentContainer {
|
||||
self.navigationPresentation = .flatModal
|
||||
|
||||
submitAppealImpl = { [weak self] in
|
||||
guard let self, let url = configuration.freezeAppealUrl else {
|
||||
guard let self, let navigationController = self.navigationController as? NavigationController, let url = configuration.freezeAppealUrl else {
|
||||
return
|
||||
}
|
||||
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: url, forceExternal: false, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: self.navigationController as? NavigationController, dismissInput: {})
|
||||
Queue.mainQueue().after(0.4) {
|
||||
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: url, forceExternal: false, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: navigationController, dismissInput: {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -212,7 +212,7 @@ final class GreetingMessageListItemComponent: Component {
|
||||
},
|
||||
openPhotoSetup: {
|
||||
},
|
||||
openAdInfo: { _ in
|
||||
openAdInfo: { _, _ in
|
||||
},
|
||||
openAccountFreezeInfo: {
|
||||
}
|
||||
|
||||
@ -233,7 +233,7 @@ final class QuickReplySetupScreenComponent: Component {
|
||||
},
|
||||
openPhotoSetup: {
|
||||
},
|
||||
openAdInfo: { _ in
|
||||
openAdInfo: { _, _ in
|
||||
},
|
||||
openAccountFreezeInfo: {
|
||||
}
|
||||
|
||||
@ -112,14 +112,24 @@ final class ChatbotSetupScreenComponent: Component {
|
||||
|
||||
final class Permission {
|
||||
var id: String
|
||||
var key: TelegramBusinessBotRights?
|
||||
var title: String
|
||||
var value: Bool?
|
||||
var enabled: Bool
|
||||
var subpermissions: [Permission]?
|
||||
var expanded: Bool?
|
||||
|
||||
init(id: String, title: String, value: Bool? = nil, enabled: Bool = true, subpermissions: [Permission]? = nil, expanded: Bool? = nil) {
|
||||
init(
|
||||
id: String,
|
||||
key: TelegramBusinessBotRights? = nil,
|
||||
title: String,
|
||||
value: Bool? = nil,
|
||||
enabled: Bool = true,
|
||||
subpermissions: [Permission]? = nil,
|
||||
expanded: Bool? = nil
|
||||
) {
|
||||
self.id = id
|
||||
self.key = key
|
||||
self.title = title
|
||||
self.value = value
|
||||
self.enabled = enabled
|
||||
@ -162,7 +172,6 @@ final class ChatbotSetupScreenComponent: Component {
|
||||
)
|
||||
|
||||
private var permissions: [Permission] = []
|
||||
|
||||
private var botRights: TelegramBusinessBotRights = []
|
||||
|
||||
override init(frame: CGRect) {
|
||||
@ -184,30 +193,6 @@ final class ChatbotSetupScreenComponent: Component {
|
||||
self.addSubview(self.scrollView)
|
||||
|
||||
self.scrollView.layer.addSublayer(self.topOverscrollLayer)
|
||||
|
||||
self.permissions = [
|
||||
Permission(id: "message", title: "Manage Messages", subpermissions: [
|
||||
Permission(id: "read", title: "Read Messages", value: true, enabled: false),
|
||||
Permission(id: "reply", title: "Reply to Messages", value: true),
|
||||
Permission(id: "mark", title: "Mark Messages as Read", value: true),
|
||||
Permission(id: "deleteSent", title: "Delete Sent Messages", value: true),
|
||||
Permission(id: "deleteReceived", title: "Delete Received Messages", value: true)
|
||||
], expanded: false),
|
||||
Permission(id: "profile", title: "Manage Profile", subpermissions: [
|
||||
Permission(id: "name", title: "Edit Name", value: true),
|
||||
Permission(id: "bio", title: "Edit Bio", value: true),
|
||||
Permission(id: "avatar", title: "Edit Profile Picture", value: true),
|
||||
Permission(id: "username", title: "Edit Username", value: true)
|
||||
], expanded: false),
|
||||
Permission(id: "gifts", title: "Manage Gifts and Stars", subpermissions: [
|
||||
Permission(id: "view", title: "View Gifts", value: true),
|
||||
Permission(id: "sell", title: "Sell Gifts", value: true),
|
||||
Permission(id: "settings", title: "Change Gift Settings", value: true),
|
||||
Permission(id: "transfer", title: "Transfer and Upgrade Gifts", value: true),
|
||||
Permission(id: "transferStars", title: "Transfer Stars", value: true)
|
||||
], expanded: false),
|
||||
Permission(id: "stories", title: "Manage Stories", value: true)
|
||||
]
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
@ -250,7 +235,7 @@ final class ChatbotSetupScreenComponent: Component {
|
||||
let _ = component.context.engine.accountData.setAccountConnectedBot(bot: TelegramAccountConnectedBot(
|
||||
id: peer.id,
|
||||
recipients: recipients,
|
||||
rights: []
|
||||
rights: self.botRights
|
||||
)).startStandalone()
|
||||
} else {
|
||||
let _ = component.context.engine.accountData.setAccountConnectedBot(bot: nil).startStandalone()
|
||||
@ -526,13 +511,17 @@ final class ChatbotSetupScreenComponent: Component {
|
||||
self.isUpdating = false
|
||||
}
|
||||
|
||||
let environment = environment[EnvironmentType.self].value
|
||||
let themeUpdated = self.environment?.theme !== environment.theme
|
||||
self.environment = environment
|
||||
|
||||
if self.component == nil {
|
||||
if let bot = component.initialData.bot, let botPeer = component.initialData.botPeer, let addressName = botPeer.addressName {
|
||||
self.botResolutionState = BotResolutionState(query: addressName, state: .found(peer: botPeer, isInstalled: true))
|
||||
self.resetQueryText = addressName.lowercased()
|
||||
|
||||
self.botRights = bot.rights
|
||||
|
||||
|
||||
let initialRecipients = bot.recipients
|
||||
|
||||
var mappedCategories = Set<AdditionalPeerList.Category>()
|
||||
@ -571,12 +560,32 @@ final class ChatbotSetupScreenComponent: Component {
|
||||
|
||||
self.hasAccessToAllChatsByDefault = initialRecipients.exclude
|
||||
}
|
||||
|
||||
self.permissions = [
|
||||
Permission(id: "message", title: environment.strings.ChatbotSetup_Rights_ManageMessages, subpermissions: [
|
||||
Permission(id: "read", title: environment.strings.ChatbotSetup_Rights_ReadMessages, value: true, enabled: false),
|
||||
Permission(id: "reply", key: .reply, title: environment.strings.ChatbotSetup_Rights_ReplyToMessages),
|
||||
Permission(id: "mark", key: .readMessages, title: environment.strings.ChatbotSetup_Rights_MarkAsRead),
|
||||
Permission(id: "deleteSent", key: .deleteSentMessages, title: environment.strings.ChatbotSetup_Rights_DeleteSentMessages),
|
||||
Permission(id: "deleteReceived", key: .deleteReceivedMessages, title: environment.strings.ChatbotSetup_Rights_DeleteReceivedMessages)
|
||||
], expanded: false),
|
||||
Permission(id: "profile", title: environment.strings.ChatbotSetup_Rights_ManageProfile, subpermissions: [
|
||||
Permission(id: "name", key: .editName, title: environment.strings.ChatbotSetup_Rights_EditName),
|
||||
Permission(id: "bio", key: .editBio, title: environment.strings.ChatbotSetup_Rights_EditBio),
|
||||
Permission(id: "avatar", key: .editProfilePhoto, title: environment.strings.ChatbotSetup_Rights_EditProfilePhoto),
|
||||
Permission(id: "username", key: .editUsername, title: environment.strings.ChatbotSetup_Rights_EditUsername)
|
||||
], expanded: false),
|
||||
Permission(id: "gifts", title: environment.strings.ChatbotSetup_Rights_ManageGiftsAndStars, subpermissions: [
|
||||
Permission(id: "view", key: .viewGifts, title: environment.strings.ChatbotSetup_Rights_ViewGifts),
|
||||
Permission(id: "sell", key: .sellGifts, title: environment.strings.ChatbotSetup_Rights_SellGifts),
|
||||
Permission(id: "settings", key: .changeGiftSettings, title: environment.strings.ChatbotSetup_Rights_ChangeGiftSettings),
|
||||
Permission(id: "transfer", key: .transferAndUpgradeGifts, title: environment.strings.ChatbotSetup_Rights_TransferAndUpgradeGifts),
|
||||
Permission(id: "transferStars", key: .transferStars, title: environment.strings.ChatbotSetup_Rights_TransferStars)
|
||||
], expanded: false),
|
||||
Permission(id: "stories", key: .manageStories, title: environment.strings.ChatbotSetup_Rights_ManageStories)
|
||||
]
|
||||
}
|
||||
|
||||
let environment = environment[EnvironmentType.self].value
|
||||
let themeUpdated = self.environment?.theme !== environment.theme
|
||||
self.environment = environment
|
||||
|
||||
|
||||
self.component = component
|
||||
self.state = state
|
||||
|
||||
@ -732,6 +741,7 @@ final class ChatbotSetupScreenComponent: Component {
|
||||
if case let .user(user) = peer, let botInfo = user.botInfo, botInfo.flags.contains(.isBusiness) {
|
||||
botResolutionState.state = .found(peer: peer, isInstalled: true)
|
||||
self.botResolutionState = botResolutionState
|
||||
self.botRights = .All
|
||||
self.state?.updated(transition: .spring(duration: 0.3))
|
||||
} else {
|
||||
self.environment?.controller()?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: presentationData.strings.ChatbotSetup_ErrorBotNotBusinessCapable, actions: [
|
||||
@ -1027,158 +1037,199 @@ final class ChatbotSetupScreenComponent: Component {
|
||||
if !self.hasAccessToAllChatsByDefault {
|
||||
contentHeight += excludedUsersContentHeight
|
||||
}
|
||||
|
||||
var permissionsItems: [AnyComponentWithIdentity<Empty>] = []
|
||||
|
||||
for permission in self.permissions {
|
||||
var value = permission.value == true
|
||||
|
||||
var titleItems: [AnyComponentWithIdentity<Empty>] = []
|
||||
titleItems.append(
|
||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: permission.title,
|
||||
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||
textColor: environment.theme.list.itemPrimaryTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 1
|
||||
)))
|
||||
)
|
||||
|
||||
if let subpermissions = permission.subpermissions {
|
||||
value = false
|
||||
var selectedCount = 0
|
||||
for subpermission in subpermissions {
|
||||
if subpermission.value == true {
|
||||
value = true
|
||||
selectedCount += 1
|
||||
}
|
||||
if case .found(_, true) = self.botResolutionState?.state {
|
||||
var permissionsItems: [AnyComponentWithIdentity<Empty>] = []
|
||||
for permission in self.permissions {
|
||||
var value: Bool
|
||||
if let key = permission.key {
|
||||
value = self.botRights.contains(key)
|
||||
} else {
|
||||
value = permission.value == true
|
||||
}
|
||||
|
||||
var titleItems: [AnyComponentWithIdentity<Empty>] = []
|
||||
titleItems.append(
|
||||
AnyComponentWithIdentity(id: AnyHashable(1), component: AnyComponent(MultilineTextComponent(
|
||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: "\(selectedCount)/\(subpermissions.count)",
|
||||
font: Font.with(size: presentationData.listsFontSize.baseDisplaySize / 17.0 * 13.0, design: .round, weight: .semibold),
|
||||
string: permission.title,
|
||||
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||
textColor: environment.theme.list.itemPrimaryTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 1
|
||||
)))
|
||||
)
|
||||
titleItems.append(
|
||||
AnyComponentWithIdentity(id: AnyHashable(2), component: AnyComponent(BundleIconComponent(
|
||||
name: "Item List/ExpandingItemVerticalRegularArrow",
|
||||
tintColor: environment.theme.list.itemPrimaryTextColor,
|
||||
flipVertically: permission.expanded == true
|
||||
)))
|
||||
)
|
||||
}
|
||||
permissionsItems.append(
|
||||
AnyComponentWithIdentity(id: permission.id, component: AnyComponent(ListActionItemComponent(
|
||||
theme: environment.theme,
|
||||
title: AnyComponent(HStack(titleItems, spacing: 6.0)),
|
||||
accessory: .toggle(ListActionItemComponent.Toggle(style: .icons, isOn: value, action: { [weak self] value in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let subpermissions = permission.subpermissions {
|
||||
for subpermission in subpermissions {
|
||||
if subpermission.enabled {
|
||||
subpermission.value = value
|
||||
}
|
||||
|
||||
if let subpermissions = permission.subpermissions {
|
||||
value = true
|
||||
var selectedCount = 0
|
||||
for subpermission in subpermissions {
|
||||
if let key = subpermission.key {
|
||||
if self.botRights.contains(key) {
|
||||
selectedCount += 1
|
||||
} else {
|
||||
value = false
|
||||
}
|
||||
} else if let value = permission.value {
|
||||
permission.value = value
|
||||
} else if subpermission.value == true {
|
||||
selectedCount += 1
|
||||
}
|
||||
self.state?.updated(transition: .spring(duration: 0.4))
|
||||
})),
|
||||
action: permission.subpermissions != nil ? { [weak self] _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
var scrollToBottom = false
|
||||
if let expanded = permission.expanded {
|
||||
permission.expanded = !expanded
|
||||
if !expanded {
|
||||
scrollToBottom = true
|
||||
}
|
||||
}
|
||||
self.state?.updated(transition: .spring(duration: 0.4))
|
||||
if scrollToBottom {
|
||||
self.scrollView.setContentOffset(CGPoint(x: 0.0, y: self.scrollView.contentSize.height - self.scrollView.bounds.height), animated: true)
|
||||
}
|
||||
} : nil
|
||||
)))
|
||||
)
|
||||
|
||||
if let subpermissions = permission.subpermissions, permission.expanded == true {
|
||||
for subpermission in subpermissions {
|
||||
permissionsItems.append(
|
||||
AnyComponentWithIdentity(id: subpermission.id, component: AnyComponent(ListActionItemComponent(
|
||||
theme: environment.theme,
|
||||
title: AnyComponent(VStack([
|
||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: subpermission.title,
|
||||
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||
textColor: environment.theme.list.itemPrimaryTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 1
|
||||
))),
|
||||
], alignment: .left, spacing: 2.0)),
|
||||
leftIcon: .check(ListActionItemComponent.LeftIcon.Check(isSelected: subpermission.value == true, isEnabled: subpermission.enabled, toggle: nil)),
|
||||
accessory: nil,
|
||||
action: subpermission.enabled ? { [weak self] _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let value = subpermission.value {
|
||||
subpermission.value = !value
|
||||
}
|
||||
self.state?.updated(transition: .spring(duration: 0.4))
|
||||
} : nil
|
||||
}
|
||||
titleItems.append(
|
||||
AnyComponentWithIdentity(id: AnyHashable(1), component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: "\(selectedCount)/\(subpermissions.count)",
|
||||
font: Font.with(size: presentationData.listsFontSize.baseDisplaySize / 17.0 * 13.0, design: .round, weight: .semibold),
|
||||
textColor: environment.theme.list.itemPrimaryTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 1
|
||||
)))
|
||||
)
|
||||
titleItems.append(
|
||||
AnyComponentWithIdentity(id: AnyHashable(2), component: AnyComponent(BundleIconComponent(
|
||||
name: "Item List/ExpandingItemVerticalRegularArrow",
|
||||
tintColor: environment.theme.list.itemPrimaryTextColor,
|
||||
flipVertically: permission.expanded == true
|
||||
)))
|
||||
)
|
||||
}
|
||||
//permissionsItems.append(AnyComponentWithIdentity(id: "\(permission.id)_sub", component: AnyComponent(VStack(stackItems, spacing: 0.0))))
|
||||
permissionsItems.append(
|
||||
AnyComponentWithIdentity(id: permission.id, component: AnyComponent(ListActionItemComponent(
|
||||
theme: environment.theme,
|
||||
title: AnyComponent(HStack(titleItems, spacing: 6.0)),
|
||||
accessory: .toggle(ListActionItemComponent.Toggle(style: .icons, isOn: value, action: { [weak self] value in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let subpermissions = permission.subpermissions {
|
||||
for subpermission in subpermissions {
|
||||
if subpermission.enabled {
|
||||
if let key = subpermission.key {
|
||||
if value {
|
||||
self.botRights.insert(key)
|
||||
} else {
|
||||
self.botRights.remove(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let key = permission.key {
|
||||
if value {
|
||||
self.botRights.insert(key)
|
||||
} else {
|
||||
self.botRights.remove(key)
|
||||
}
|
||||
}
|
||||
self.state?.updated(transition: .spring(duration: 0.4))
|
||||
})),
|
||||
action: permission.subpermissions != nil ? { [weak self] _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
var scrollToBottom = false
|
||||
if let expanded = permission.expanded {
|
||||
permission.expanded = !expanded
|
||||
if !expanded {
|
||||
scrollToBottom = true
|
||||
}
|
||||
}
|
||||
self.state?.updated(transition: .spring(duration: 0.4))
|
||||
if scrollToBottom {
|
||||
self.scrollView.setContentOffset(CGPoint(x: 0.0, y: self.scrollView.contentSize.height - self.scrollView.bounds.height), animated: true)
|
||||
}
|
||||
} : nil
|
||||
)))
|
||||
)
|
||||
|
||||
if let subpermissions = permission.subpermissions, permission.expanded == true {
|
||||
for subpermission in subpermissions {
|
||||
var value = false
|
||||
if let key = subpermission.key {
|
||||
value = self.botRights.contains(key)
|
||||
} else if subpermission.value == true {
|
||||
value = true
|
||||
}
|
||||
|
||||
permissionsItems.append(
|
||||
AnyComponentWithIdentity(id: subpermission.id, component: AnyComponent(ListActionItemComponent(
|
||||
theme: environment.theme,
|
||||
title: AnyComponent(VStack([
|
||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: subpermission.title,
|
||||
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||
textColor: environment.theme.list.itemPrimaryTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 1
|
||||
))),
|
||||
], alignment: .left, spacing: 2.0)),
|
||||
leftIcon: .check(ListActionItemComponent.LeftIcon.Check(isSelected: value, isEnabled: subpermission.enabled, toggle: nil)),
|
||||
accessory: nil,
|
||||
action: subpermission.enabled ? { [weak self] _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let key = subpermission.key {
|
||||
if !value {
|
||||
self.botRights.insert(key)
|
||||
} else {
|
||||
self.botRights.remove(key)
|
||||
}
|
||||
}
|
||||
self.state?.updated(transition: .spring(duration: 0.4))
|
||||
} : nil
|
||||
)))
|
||||
)
|
||||
}
|
||||
//permissionsItems.append(AnyComponentWithIdentity(id: "\(permission.id)_sub", component: AnyComponent(VStack(stackItems, spacing: 0.0))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
let permissionsSectionSize = self.permissionsSection.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(ListSectionComponent(
|
||||
theme: environment.theme,
|
||||
header: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: environment.strings.ChatbotSetup_PermissionsSectionHeader,
|
||||
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
|
||||
textColor: environment.theme.list.freeTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 0
|
||||
)),
|
||||
footer: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: environment.strings.ChatbotSetup_PermissionsSectionFooter,
|
||||
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
|
||||
textColor: environment.theme.list.freeTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 0
|
||||
)),
|
||||
items: permissionsItems
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
|
||||
)
|
||||
let permissionsSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: permissionsSectionSize)
|
||||
if let permissionsSectionView = self.permissionsSection.view {
|
||||
if permissionsSectionView.superview == nil {
|
||||
self.scrollView.addSubview(permissionsSectionView)
|
||||
|
||||
var permissionsTransition = transition
|
||||
if self.permissionsSection.view?.superview == nil {
|
||||
permissionsTransition = .immediate
|
||||
}
|
||||
transition.setFrame(view: permissionsSectionView, frame: permissionsSectionFrame)
|
||||
|
||||
let permissionsSectionSize = self.permissionsSection.update(
|
||||
transition: permissionsTransition,
|
||||
component: AnyComponent(ListSectionComponent(
|
||||
theme: environment.theme,
|
||||
header: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: environment.strings.ChatbotSetup_PermissionsSectionHeader,
|
||||
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
|
||||
textColor: environment.theme.list.freeTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 0
|
||||
)),
|
||||
footer: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: environment.strings.ChatbotSetup_PermissionsSectionFooter,
|
||||
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
|
||||
textColor: environment.theme.list.freeTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 0
|
||||
)),
|
||||
items: permissionsItems
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
|
||||
)
|
||||
let permissionsSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: permissionsSectionSize)
|
||||
if let permissionsSectionView = self.permissionsSection.view {
|
||||
if permissionsSectionView.superview == nil {
|
||||
self.scrollView.addSubview(permissionsSectionView)
|
||||
|
||||
permissionsSectionView.alpha = 1.0
|
||||
transition.animateAlpha(view: permissionsSectionView, from: 0.0, to: 1.0)
|
||||
}
|
||||
permissionsTransition.setFrame(view: permissionsSectionView, frame: permissionsSectionFrame)
|
||||
}
|
||||
contentHeight += permissionsSectionSize.height
|
||||
} else if let permissionsSectionView = self.permissionsSection.view {
|
||||
transition.setAlpha(view: permissionsSectionView, alpha: 0.0, completion: { _ in
|
||||
permissionsSectionView.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
contentHeight += permissionsSectionSize.height
|
||||
|
||||
contentHeight += bottomContentInset
|
||||
contentHeight += environment.safeInsets.bottom
|
||||
|
||||
@ -875,7 +875,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, ASScrollViewDelegate
|
||||
}, editPeer: { _ in
|
||||
}, openWebApp: { _ in
|
||||
}, openPhotoSetup: {
|
||||
}, openAdInfo: { _ in
|
||||
}, openAdInfo: { _, _ in
|
||||
}, openAccountFreezeInfo: {
|
||||
})
|
||||
let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true)
|
||||
|
||||
@ -15,7 +15,7 @@ import TelegramPresentationData
|
||||
import TelegramNotices
|
||||
|
||||
extension ChatControllerImpl {
|
||||
func presentAccountFrozenInfoIfNeeded() -> Bool {
|
||||
func presentAccountFrozenInfoIfNeeded(delay: Bool = false) -> Bool {
|
||||
if self.context.isFrozen {
|
||||
let accountFreezeConfiguration = AccountFreezeConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 })
|
||||
if let freezeAppealUrl = accountFreezeConfiguration.freezeAppealUrl {
|
||||
@ -24,7 +24,16 @@ extension ChatControllerImpl {
|
||||
return false
|
||||
}
|
||||
}
|
||||
self.push(self.context.sharedContext.makeAccountFreezeInfoScreen(context: self.context))
|
||||
let present = {
|
||||
self.push(self.context.sharedContext.makeAccountFreezeInfoScreen(context: self.context))
|
||||
}
|
||||
if delay {
|
||||
Queue.mainQueue().after(0.3) {
|
||||
present()
|
||||
}
|
||||
} else {
|
||||
present()
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@ -1866,7 +1866,7 @@ extension ChatControllerImpl {
|
||||
return
|
||||
}
|
||||
|
||||
guard !strongSelf.presentAccountFrozenInfoIfNeeded() else {
|
||||
guard !strongSelf.presentAccountFrozenInfoIfNeeded(delay: true) else {
|
||||
completion(.immediate, {})
|
||||
return
|
||||
}
|
||||
@ -2120,7 +2120,7 @@ extension ChatControllerImpl {
|
||||
})
|
||||
}, deleteMessages: { [weak self] messages, contextController, completion in
|
||||
if let strongSelf = self, !messages.isEmpty {
|
||||
guard !strongSelf.presentAccountFrozenInfoIfNeeded() else {
|
||||
guard !strongSelf.presentAccountFrozenInfoIfNeeded(delay: true) else {
|
||||
completion(.default)
|
||||
return
|
||||
}
|
||||
@ -2192,6 +2192,10 @@ extension ChatControllerImpl {
|
||||
}
|
||||
}, forwardMessages: { [weak self] messages in
|
||||
if let strongSelf = self, !messages.isEmpty {
|
||||
guard !strongSelf.presentAccountFrozenInfoIfNeeded(delay: true) else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.commitPurposefulAction()
|
||||
let forwardMessageIds = messages.map { $0.id }.sorted()
|
||||
strongSelf.forwardMessages(messageIds: forwardMessageIds)
|
||||
@ -3229,6 +3233,11 @@ extension ChatControllerImpl {
|
||||
self?.unblockPeer()
|
||||
}, pinMessage: { [weak self] messageId, contextController in
|
||||
if let strongSelf = self, let currentPeerId = strongSelf.chatLocation.peerId {
|
||||
guard !strongSelf.presentAccountFrozenInfoIfNeeded(delay: true) else {
|
||||
contextController?.dismiss(completion: nil)
|
||||
return
|
||||
}
|
||||
|
||||
if let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer {
|
||||
if strongSelf.canManagePin() {
|
||||
let pinAction: (Bool, Bool) -> Void = { notify, forThisPeerOnlyIfPossible in
|
||||
|
||||
@ -132,6 +132,10 @@ extension ChatControllerImpl {
|
||||
case .cancelMessageSelection:
|
||||
self.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState { $0.withoutSelectionState() } })
|
||||
case .clearHistory:
|
||||
guard !self.presentAccountFrozenInfoIfNeeded() else {
|
||||
return
|
||||
}
|
||||
|
||||
if case let .peer(peerId) = self.chatLocation {
|
||||
let beginClear: (InteractiveHistoryClearingType) -> Void = { [weak self] type in
|
||||
self?.beginClearHistory(type: type)
|
||||
|
||||
@ -333,7 +333,7 @@ extension ChatControllerImpl {
|
||||
}
|
||||
|
||||
controller?.dismissWithoutContent()
|
||||
guard !self.presentAccountFrozenInfoIfNeeded() else {
|
||||
guard !self.presentAccountFrozenInfoIfNeeded(delay: true) else {
|
||||
return
|
||||
}
|
||||
self.presentTagPremiumPaywall()
|
||||
@ -344,7 +344,7 @@ extension ChatControllerImpl {
|
||||
return
|
||||
}
|
||||
|
||||
guard !self.presentAccountFrozenInfoIfNeeded() else {
|
||||
guard !self.presentAccountFrozenInfoIfNeeded(delay: true) else {
|
||||
controller?.dismiss(completion: {})
|
||||
return
|
||||
}
|
||||
|
||||
@ -50,17 +50,22 @@ extension ChatControllerImpl {
|
||||
func enqueueGifData(_ data: Data) {
|
||||
self.enqueueMediaMessageDisposable.set((legacyEnqueueGifMessage(account: self.context.account, data: data) |> deliverOnMainQueue).startStrict(next: { [weak self] message in
|
||||
if let strongSelf = self {
|
||||
let replyMessageSubject = strongSelf.presentationInterfaceState.interfaceState.replyMessageSubject
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil) }
|
||||
})
|
||||
strongSelf.presentPaidMessageAlertIfNeeded(completion: { [weak self] postpone in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
}, nil)
|
||||
strongSelf.sendMessages([message].map { $0.withUpdatedReplyToMessageId(replyMessageSubject?.subjectModel) })
|
||||
let replyMessageSubject = strongSelf.presentationInterfaceState.interfaceState.replyMessageSubject
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil) }
|
||||
})
|
||||
}
|
||||
}, nil)
|
||||
strongSelf.sendMessages([message].map { $0.withUpdatedReplyToMessageId(replyMessageSubject?.subjectModel) })
|
||||
})
|
||||
}
|
||||
}))
|
||||
}
|
||||
@ -68,17 +73,22 @@ extension ChatControllerImpl {
|
||||
func enqueueVideoData(_ data: Data) {
|
||||
self.enqueueMediaMessageDisposable.set((legacyEnqueueGifMessage(account: self.context.account, data: data) |> deliverOnMainQueue).startStrict(next: { [weak self] message in
|
||||
if let strongSelf = self {
|
||||
let replyMessageSubject = strongSelf.presentationInterfaceState.interfaceState.replyMessageSubject
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil) }
|
||||
})
|
||||
strongSelf.presentPaidMessageAlertIfNeeded(completion: { [weak self] postpone in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
}, nil)
|
||||
strongSelf.sendMessages([message].map { $0.withUpdatedReplyToMessageId(replyMessageSubject?.subjectModel) })
|
||||
let replyMessageSubject = strongSelf.presentationInterfaceState.interfaceState.replyMessageSubject
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil) }
|
||||
})
|
||||
}
|
||||
}, nil)
|
||||
strongSelf.sendMessages([message].map { $0.withUpdatedReplyToMessageId(replyMessageSubject?.subjectModel) })
|
||||
})
|
||||
}
|
||||
}))
|
||||
}
|
||||
@ -98,17 +108,22 @@ extension ChatControllerImpl {
|
||||
let media = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: Int64.random(in: Int64.min ... Int64.max)), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "image/webp", size: Int64(data.count), attributes: fileAttributes, alternativeRepresentations: [])
|
||||
let message = EnqueueMessage.message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: media), threadId: strongSelf.chatLocation.threadId, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])
|
||||
|
||||
let replyMessageSubject = strongSelf.presentationInterfaceState.interfaceState.replyMessageSubject
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil) }
|
||||
})
|
||||
strongSelf.presentPaidMessageAlertIfNeeded(completion: { [weak self] postpone in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
}, nil)
|
||||
strongSelf.sendMessages([message].map { $0.withUpdatedReplyToMessageId(replyMessageSubject?.subjectModel) })
|
||||
let replyMessageSubject = strongSelf.presentationInterfaceState.interfaceState.replyMessageSubject
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil) }
|
||||
})
|
||||
}
|
||||
}, nil)
|
||||
strongSelf.sendMessages([message].map { $0.withUpdatedReplyToMessageId(replyMessageSubject?.subjectModel) }, postpone: postpone)
|
||||
})
|
||||
}
|
||||
}))
|
||||
}
|
||||
@ -116,23 +131,28 @@ extension ChatControllerImpl {
|
||||
func enqueueStickerFile(_ file: TelegramMediaFile) {
|
||||
let message = EnqueueMessage.message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: file), threadId: self.chatLocation.threadId, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])
|
||||
|
||||
let replyMessageSubject = self.presentationInterfaceState.interfaceState.replyMessageSubject
|
||||
self.chatDisplayNode.setupSendActionOnViewUpdate({ [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil) }
|
||||
})
|
||||
self.presentPaidMessageAlertIfNeeded(completion: { [weak self] postpone in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
}, nil)
|
||||
self.sendMessages([message].map { $0.withUpdatedReplyToMessageId(replyMessageSubject?.subjectModel) })
|
||||
|
||||
Queue.mainQueue().after(3.0) {
|
||||
if let message = self.chatDisplayNode.historyNode.lastVisbleMesssage(), let file = message.media.first(where: { $0 is TelegramMediaFile }) as? TelegramMediaFile, file.isSticker {
|
||||
self.context.engine.stickers.addRecentlyUsedSticker(fileReference: .message(message: MessageReference(message), media: file))
|
||||
let replyMessageSubject = self.presentationInterfaceState.interfaceState.replyMessageSubject
|
||||
self.chatDisplayNode.setupSendActionOnViewUpdate({ [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil) }
|
||||
})
|
||||
}
|
||||
}, nil)
|
||||
self.sendMessages([message].map { $0.withUpdatedReplyToMessageId(replyMessageSubject?.subjectModel) })
|
||||
|
||||
Queue.mainQueue().after(3.0) {
|
||||
if let message = self.chatDisplayNode.historyNode.lastVisbleMesssage(), let file = message.media.first(where: { $0 is TelegramMediaFile }) as? TelegramMediaFile, file.isSticker {
|
||||
self.context.engine.stickers.addRecentlyUsedSticker(fileReference: .message(message: MessageReference(message), media: file))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func enqueueAnimatedStickerData(_ data: Data) {
|
||||
@ -223,9 +243,7 @@ extension ChatControllerImpl {
|
||||
fileAttributes.append(.Video(duration: animatedImage.duration, size: PixelDimensions(width: 512, height: 512), flags: [], preloadSize: nil, coverTime: nil, videoCodec: nil))
|
||||
|
||||
let previewRepresentations: [TelegramMediaImageRepresentation] = []
|
||||
// if let thumbnailResource {
|
||||
// previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: dimensions, resource: thumbnailResource, progressiveSizes: [], immediateThumbnailData: nil))
|
||||
// }
|
||||
|
||||
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
|
||||
self.context.account.postbox.mediaBox.copyResourceData(resource.id, fromTempPath: path)
|
||||
|
||||
@ -235,7 +253,5 @@ extension ChatControllerImpl {
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
// self.stickerVideoExport = videoExport
|
||||
}
|
||||
}
|
||||
|
||||
@ -3402,7 +3402,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
guard !self.presentAccountFrozenInfoIfNeeded() else {
|
||||
guard !self.presentAccountFrozenInfoIfNeeded(delay: true) else {
|
||||
return
|
||||
}
|
||||
self.presentScheduleTimePicker(completion: { [weak self] time in
|
||||
@ -3433,7 +3433,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
guard !self.presentAccountFrozenInfoIfNeeded() else {
|
||||
guard !self.presentAccountFrozenInfoIfNeeded(delay: true) else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -6397,7 +6397,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if case let .known(value) = cachedData.businessIntro {
|
||||
businessIntro = value
|
||||
}
|
||||
alwaysShowGiftButton = cachedData.flags.contains(.displayGiftButton)
|
||||
if cachedData.disallowedGifts != .All {
|
||||
alwaysShowGiftButton = cachedData.flags.contains(.displayGiftButton)
|
||||
}
|
||||
} else if let cachedData = peerView.cachedData as? CachedGroupData {
|
||||
var invitedBy: Peer?
|
||||
if let invitedByPeerId = cachedData.invitedBy {
|
||||
@ -9265,8 +9267,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
if let value = value {
|
||||
self.present(UndoOverlayController(presentationData: self.presentationData, content: .dice(dice: dice, context: self.context, text: value, action: canSendMessagesToChat(self.presentationInterfaceState) ? self.presentationData.strings.Conversation_SendDice : nil), elevatedLayout: false, action: { [weak self] action in
|
||||
if let strongSelf = self, canSendMessagesToChat(strongSelf.presentationInterfaceState), action == .undo {
|
||||
strongSelf.sendMessages([.message(text: "", attributes: [], inlineStickers: [:], mediaReference: AnyMediaReference.standalone(media: TelegramMediaDice(emoji: dice.emoji)), threadId: strongSelf.chatLocation.threadId, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])])
|
||||
if let self, canSendMessagesToChat(self.presentationInterfaceState), action == .undo {
|
||||
self.presentPaidMessageAlertIfNeeded(completion: { [weak self] postpone in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.sendMessages([.message(text: "", attributes: [], inlineStickers: [:], mediaReference: AnyMediaReference.standalone(media: TelegramMediaDice(emoji: dice.emoji)), threadId: self.chatLocation.threadId, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])], postpone: postpone)
|
||||
})
|
||||
}
|
||||
return false
|
||||
}), in: .current)
|
||||
|
||||
@ -559,13 +559,12 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
}, iconSource: nil, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
let _ = (context.engine.messages.reportAdMessage(peerId: message.id.peerId, opaqueId: adAttribute.opaqueId, option: nil)
|
||||
let _ = (context.engine.messages.reportAdMessage(opaqueId: adAttribute.opaqueId, option: nil)
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
if case let .options(title, options) = result {
|
||||
controllerInteraction.navigationController()?.pushViewController(
|
||||
AdsReportScreen(
|
||||
context: context,
|
||||
peerId: message.id.peerId,
|
||||
opaqueId: adAttribute.opaqueId,
|
||||
title: title,
|
||||
options: options,
|
||||
|
||||
@ -89,10 +89,9 @@ final class ChatRestrictedInputPanelNode: ChatInputPanelNode {
|
||||
if let context = self.context {
|
||||
accountFreezeConfiguration = AccountFreezeConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
|
||||
}
|
||||
//TODO:localize
|
||||
if let _ = accountFreezeConfiguration?.freezeUntilDate {
|
||||
self.textNode.attributedText = NSAttributedString(string: "You account is frozen", font: Font.semibold(15.0), textColor: interfaceState.theme.list.itemDestructiveColor)
|
||||
self.subtitleNode.attributedText = NSAttributedString(string: "Tap to view details", font: Font.regular(13.0), textColor: interfaceState.theme.chat.inputPanel.secondaryTextColor)
|
||||
self.textNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_PanelFrozenAccount_Title, font: Font.semibold(15.0), textColor: interfaceState.theme.list.itemDestructiveColor)
|
||||
self.subtitleNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_PanelFrozenAccount_Text, font: Font.regular(13.0), textColor: interfaceState.theme.chat.inputPanel.secondaryTextColor)
|
||||
isUserInteractionEnabled = true
|
||||
} else if case let .replyThread(message) = interfaceState.chatLocation, message.peerId == self.context?.account.peerId {
|
||||
self.textNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_PanelStatusAuthorHidden, font: Font.regular(13.0), textColor: interfaceState.theme.chat.inputPanel.secondaryTextColor)
|
||||
|
||||
@ -295,7 +295,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, ASScrollViewDe
|
||||
}, editPeer: { _ in
|
||||
}, openWebApp: { _ in
|
||||
}, openPhotoSetup: {
|
||||
}, openAdInfo: { _ in
|
||||
}, openAdInfo: { _, _ in
|
||||
}, openAccountFreezeInfo: {
|
||||
})
|
||||
interaction.searchTextHighightState = searchQuery
|
||||
|
||||
@ -182,7 +182,7 @@ private struct CommandChatInputContextPanelEntry: Comparable, Identifiable {
|
||||
},
|
||||
openPhotoSetup: {
|
||||
},
|
||||
openAdInfo: { _ in
|
||||
openAdInfo: { _, _ in
|
||||
},
|
||||
openAccountFreezeInfo: {
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user