mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various improvements
This commit is contained in:
parent
149805e914
commit
57e7e6906b
@ -890,7 +890,7 @@ public protocol AccountContext: AnyObject {
|
||||
|
||||
public struct PremiumConfiguration {
|
||||
public static var defaultValue: PremiumConfiguration {
|
||||
return PremiumConfiguration(isPremiumDisabled: false)
|
||||
return PremiumConfiguration(isPremiumDisabled: true)
|
||||
}
|
||||
|
||||
public let isPremiumDisabled: Bool
|
||||
|
@ -1034,14 +1034,14 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
let controller = internalChatListFilterExcludeChatsController(context: context, filter: filter, allFilters: filters, applyAutomatically: false, updated: { filter in
|
||||
skipStateAnimation = true
|
||||
updateState { state in
|
||||
var state = state
|
||||
state.additionallyIncludePeers = filter.data?.includePeers.peers ?? []
|
||||
state.additionallyExcludePeers = filter.data?.excludePeers ?? []
|
||||
state.includeCategories = filter.data?.categories ?? []
|
||||
state.excludeRead = filter.data?.excludeRead ?? false
|
||||
state.excludeMuted = filter.data?.excludeMuted ?? false
|
||||
state.excludeArchived = filter.data?.excludeArchived ?? false
|
||||
return state
|
||||
var updatedState = state
|
||||
updatedState.additionallyIncludePeers = filter.data?.includePeers.peers ?? []
|
||||
updatedState.additionallyExcludePeers = filter.data?.excludePeers ?? []
|
||||
updatedState.includeCategories = filter.data?.categories ?? []
|
||||
updatedState.excludeRead = filter.data?.excludeRead ?? false
|
||||
updatedState.excludeMuted = filter.data?.excludeMuted ?? false
|
||||
updatedState.excludeArchived = filter.data?.excludeArchived ?? false
|
||||
return updatedState
|
||||
}
|
||||
})
|
||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
@ -1125,7 +1125,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
var found = false
|
||||
for i in 0 ..< filters.count {
|
||||
if filters[i].id == updatedFilter.id, case let .filter(_, _, _, data) = filters[i] {
|
||||
var updatedData = data
|
||||
var updatedData = updatedFilter.data ?? data
|
||||
var includePeers = updatedData.includePeers
|
||||
includePeers.setPeers(state.additionallyIncludePeers)
|
||||
updatedData.includePeers = includePeers
|
||||
|
@ -1484,6 +1484,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
currentSecretIconImage = PresentationResourcesChatList.secretIcon(item.presentationData.theme)
|
||||
}
|
||||
|
||||
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: item.context.currentAppConfiguration.with { $0 })
|
||||
if !isPeerGroup && item.index.messageIndex.id.peerId != item.context.account.peerId {
|
||||
if displayAsMessage {
|
||||
switch item.content {
|
||||
@ -1495,7 +1496,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.fakeIcon(item.presentationData.theme, strings: item.presentationData.strings, type: .regular)
|
||||
} else if peer.isVerified {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
||||
} else if peer.isPremium {
|
||||
} else if peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.premiumIcon(item.presentationData.theme)
|
||||
}
|
||||
}
|
||||
@ -1509,7 +1510,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.fakeIcon(item.presentationData.theme, strings: item.presentationData.strings, type: .regular)
|
||||
} else if peer.isVerified {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
||||
} else if peer.isPremium {
|
||||
} else if peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.premiumIcon(item.presentationData.theme)
|
||||
}
|
||||
}
|
||||
|
@ -563,6 +563,8 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
}
|
||||
}
|
||||
|
||||
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: item.context.currentAppConfiguration.with { $0 })
|
||||
|
||||
var currentCredibilityIconImage: UIImage?
|
||||
switch item.peer {
|
||||
case let .peer(peer, _):
|
||||
@ -573,7 +575,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.fakeIcon(item.presentationData.theme, strings: item.presentationData.strings, type: .regular)
|
||||
} else if peer.isVerified {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
||||
} else if peer.isPremium {
|
||||
} else if peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.premiumIcon(item.presentationData.theme)
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ swift_library(
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/GZip:GZip",
|
||||
"//third-party/ZipArchive:ZipArchive",
|
||||
"//submodules/InAppPurchaseManager:InAppPurchaseManager",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -15,6 +15,7 @@ import AccountContext
|
||||
import AppBundle
|
||||
import ZipArchive
|
||||
import WebKit
|
||||
import InAppPurchaseManager
|
||||
|
||||
@objc private final class DebugControllerMailComposeDelegate: NSObject, MFMailComposeViewControllerDelegate {
|
||||
public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
|
||||
@ -86,13 +87,13 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
case experimentalBackground(Bool)
|
||||
case inlineStickers(Bool)
|
||||
case localTranscription(Bool)
|
||||
case snow(Bool)
|
||||
case playerEmbedding(Bool)
|
||||
case playlistPlayback(Bool)
|
||||
case voiceConference
|
||||
case preferredVideoCodec(Int, String, String?, Bool)
|
||||
case disableVideoAspectScaling(Bool)
|
||||
case enableVoipTcp(Bool)
|
||||
case resetInAppPurchases(PresentationTheme)
|
||||
case hostInfo(PresentationTheme, String)
|
||||
case versionInfo(PresentationTheme)
|
||||
|
||||
@ -108,7 +109,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
return DebugControllerSection.logging.rawValue
|
||||
case .enableRaiseToSpeak, .keepChatNavigationStack, .skipReadHistory, .crashOnSlowQueries:
|
||||
return DebugControllerSection.experiments.rawValue
|
||||
case .clearTips, .crash, .resetData, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .reindexUnread, .resetBiometricsData, .resetWebViewCache, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .playerEmbedding, .playlistPlayback, .voiceConference, .experimentalCompatibility, .enableDebugDataDisplay, .acceleratedStickers, .experimentalBackground, .inlineStickers, .localTranscription, .snow:
|
||||
case .clearTips, .crash, .resetData, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .reindexUnread, .resetBiometricsData, .resetWebViewCache, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .playerEmbedding, .playlistPlayback, .voiceConference, .experimentalCompatibility, .enableDebugDataDisplay, .acceleratedStickers, .experimentalBackground, .inlineStickers, .localTranscription, .resetInAppPurchases:
|
||||
return DebugControllerSection.experiments.rawValue
|
||||
case .preferredVideoCodec:
|
||||
return DebugControllerSection.videoExperiments.rawValue
|
||||
@ -187,7 +188,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
return 31
|
||||
case .localTranscription:
|
||||
return 32
|
||||
case .snow:
|
||||
case .resetInAppPurchases:
|
||||
return 33
|
||||
case .playerEmbedding:
|
||||
return 34
|
||||
@ -969,16 +970,6 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
})
|
||||
}).start()
|
||||
})
|
||||
case let .snow(value):
|
||||
return ItemListSwitchItem(presentationData: presentationData, title: "Snow", value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
let _ = arguments.sharedContext.accountManager.transaction ({ transaction in
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in
|
||||
var settings = settings?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings
|
||||
settings.snow = value
|
||||
return PreferencesEntry(settings)
|
||||
})
|
||||
}).start()
|
||||
})
|
||||
case let .playerEmbedding(value):
|
||||
return ItemListSwitchItem(presentationData: presentationData, title: "Player Embedding", value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
let _ = arguments.sharedContext.accountManager.transaction ({ transaction in
|
||||
@ -1035,6 +1026,10 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
})
|
||||
}).start()
|
||||
})
|
||||
case .resetInAppPurchases:
|
||||
return ItemListActionItem(presentationData: presentationData, title: "Reset IAP Transactions", kind: .destructive, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.context?.inAppPurchaseManager?.finishAllTransactions()
|
||||
})
|
||||
case let .hostInfo(_, string):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(string), sectionId: self.section)
|
||||
case .versionInfo:
|
||||
@ -1096,6 +1091,7 @@ private func debugControllerEntries(sharedContext: SharedAccountContext, present
|
||||
entries.append(.experimentalBackground(experimentalSettings.experimentalBackground))
|
||||
entries.append(.inlineStickers(experimentalSettings.inlineStickers))
|
||||
entries.append(.localTranscription(experimentalSettings.localTranscription))
|
||||
entries.append(.resetInAppPurchases(presentationData.theme))
|
||||
entries.append(.playerEmbedding(experimentalSettings.playerEmbedding))
|
||||
entries.append(.playlistPlayback(experimentalSettings.playlistPlayback))
|
||||
}
|
||||
|
@ -93,6 +93,14 @@ public final class InAppPurchaseManager: NSObject {
|
||||
return self.productsPromise.get()
|
||||
}
|
||||
|
||||
public func finishAllTransactions() {
|
||||
let paymentQueue = SKPaymentQueue.default()
|
||||
let transactions = paymentQueue.transactions
|
||||
for transaction in transactions {
|
||||
paymentQueue.finishTransaction(transaction)
|
||||
}
|
||||
}
|
||||
|
||||
public func buyProduct(_ product: Product, account: Account) -> Signal<PurchaseState, PurchaseError> {
|
||||
let payment = SKPayment(product: product.skProduct)
|
||||
SKPaymentQueue.default().add(payment)
|
||||
@ -159,6 +167,18 @@ extension InAppPurchaseManager: SKProductsRequestDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
private func getReceiptData() -> Data? {
|
||||
var receiptData: Data?
|
||||
if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL, FileManager.default.fileExists(atPath: appStoreReceiptURL.path) {
|
||||
do {
|
||||
receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped)
|
||||
} catch {
|
||||
Logger.shared.log("InAppPurchaseManager", "Couldn't read receipt data with error: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
return receiptData
|
||||
}
|
||||
|
||||
extension InAppPurchaseManager: SKPaymentTransactionObserver {
|
||||
public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
|
||||
for transaction in transactions {
|
||||
@ -167,23 +187,28 @@ extension InAppPurchaseManager: SKPaymentTransactionObserver {
|
||||
let transactionState: TransactionState?
|
||||
switch transaction.transactionState {
|
||||
case .purchased:
|
||||
transactionState = .purchased(transactionId: transaction.transactionIdentifier)
|
||||
if let transactionIdentifier = transaction.transactionIdentifier {
|
||||
self.disposableSet.set(
|
||||
self.engine.payments.assignAppStoreTransaction(transactionId: transactionIdentifier).start(error: { error in
|
||||
|
||||
}, completed: {
|
||||
queue.finishTransaction(transaction)
|
||||
}),
|
||||
forKey: transaction.transactionIdentifier ?? ""
|
||||
)
|
||||
if transaction.original == nil {
|
||||
transactionState = .purchased(transactionId: transaction.transactionIdentifier)
|
||||
if let transactionIdentifier = transaction.transactionIdentifier {
|
||||
self.disposableSet.set(
|
||||
self.engine.payments.assignAppStoreTransaction(transactionId: transactionIdentifier, receipt: getReceiptData() ?? Data(), restore: false).start(error: { _ in
|
||||
queue.finishTransaction(transaction)
|
||||
}, completed: {
|
||||
queue.finishTransaction(transaction)
|
||||
}),
|
||||
forKey: transaction.transactionIdentifier ?? ""
|
||||
)
|
||||
}
|
||||
} else {
|
||||
transactionState = nil
|
||||
queue.finishTransaction(transaction)
|
||||
}
|
||||
case .restored:
|
||||
transactionState = .restored(transactionId: transaction.transactionIdentifier)
|
||||
if let transactionIdentifier = transaction.transactionIdentifier {
|
||||
transactionState = .restored(transactionId: transaction.original?.transactionIdentifier)
|
||||
if let transactionIdentifier = transaction.original?.transactionIdentifier {
|
||||
self.disposableSet.set(
|
||||
self.engine.payments.assignAppStoreTransaction(transactionId: transactionIdentifier).start(error: { error in
|
||||
|
||||
self.engine.payments.assignAppStoreTransaction(transactionId: transactionIdentifier, receipt: getReceiptData() ?? Data(), restore: true).start(error: { _ in
|
||||
queue.finishTransaction(transaction)
|
||||
}, completed: {
|
||||
queue.finishTransaction(transaction)
|
||||
}),
|
||||
|
@ -358,6 +358,8 @@ public class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNo
|
||||
updatedTheme = item.presentationData.theme
|
||||
}
|
||||
|
||||
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: item.accountContext.currentAppConfiguration.with { $0 })
|
||||
|
||||
var credibilityIconImage: UIImage?
|
||||
var credibilityIconOffset: CGFloat = 4.0
|
||||
if let peer = item.peer {
|
||||
@ -369,6 +371,8 @@ public class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNo
|
||||
credibilityIconOffset = 2.0
|
||||
} else if peer.isVerified {
|
||||
credibilityIconImage = PresentationResourcesItemList.verifiedPeerIcon(item.presentationData.theme)
|
||||
} else if peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
||||
credibilityIconImage = PresentationResourcesChatList.premiumIcon(item.presentationData.theme)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -603,6 +603,8 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
var updatedLabelBadgeImage: UIImage?
|
||||
var currentCredibilityIconImage: UIImage?
|
||||
|
||||
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: item.context.currentAppConfiguration.with { $0 })
|
||||
|
||||
if case .threatSelfAsSaved = item.aliasHandling, item.peer.id == item.context.account.peerId {
|
||||
|
||||
} else {
|
||||
@ -612,7 +614,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.fakeIcon(item.presentationData.theme, strings: item.presentationData.strings, type: .regular)
|
||||
} else if item.peer.isVerified {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
||||
} else if item.peer.isPremium {
|
||||
} else if item.peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.premiumIcon(item.presentationData.theme)
|
||||
}
|
||||
}
|
||||
|
@ -622,9 +622,16 @@ private struct ChannelVisibilityControllerState: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private func channelVisibilityControllerEntries(presentationData: PresentationData, mode: ChannelVisibilityControllerMode, view: PeerView, publicChannelsToRevoke: [Peer]?, importers: PeerInvitationImportersState?, state: ChannelVisibilityControllerState, limits: EngineConfiguration.UserLimits, premiumLimits: EngineConfiguration.UserLimits, isPremium: Bool) -> [ChannelVisibilityEntry] {
|
||||
private func channelVisibilityControllerEntries(presentationData: PresentationData, mode: ChannelVisibilityControllerMode, view: PeerView, publicChannelsToRevoke: [Peer]?, importers: PeerInvitationImportersState?, state: ChannelVisibilityControllerState, limits: EngineConfiguration.UserLimits, premiumLimits: EngineConfiguration.UserLimits, isPremium: Bool, isPremiumDisabled: Bool) -> [ChannelVisibilityEntry] {
|
||||
var entries: [ChannelVisibilityEntry] = []
|
||||
|
||||
let isInitialSetup: Bool
|
||||
if case .initialSetup = mode {
|
||||
isInitialSetup = true
|
||||
} else {
|
||||
isInitialSetup = false
|
||||
}
|
||||
|
||||
if let peer = view.peers[view.peerId] as? TelegramChannel {
|
||||
var isGroup = false
|
||||
if case .group = peer.info {
|
||||
@ -721,36 +728,30 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
||||
}
|
||||
}
|
||||
|
||||
switch selectedType {
|
||||
case .publicChannel:
|
||||
var displayAvailability = false
|
||||
if peer.addressName == nil {
|
||||
displayAvailability = publicChannelsToRevoke != nil && !(publicChannelsToRevoke!.isEmpty)
|
||||
}
|
||||
|
||||
if !"".isEmpty && displayAvailability {
|
||||
if let publicChannelsToRevoke = publicChannelsToRevoke {
|
||||
// entries.append(.linksLimitInfo(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesOrExtendInfo("\(20)").string, limits.maxPublicLinksCount, premiumLimits.maxPublicLinksCount))
|
||||
|
||||
var index: Int32 = 0
|
||||
for peer in publicChannelsToRevoke.sorted(by: { lhs, rhs in
|
||||
var lhsDate: Int32 = 0
|
||||
var rhsDate: Int32 = 0
|
||||
if let lhs = lhs as? TelegramChannel {
|
||||
lhsDate = lhs.creationDate
|
||||
}
|
||||
if let rhs = rhs as? TelegramChannel {
|
||||
rhsDate = rhs.creationDate
|
||||
}
|
||||
return lhsDate > rhsDate
|
||||
}) {
|
||||
entries.append(.existingLinkPeerItem(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, peer, ItemListPeerItemEditing(editable: true, editing: true, revealed: state.revealedRevokePeerId == peer.id), state.revokingPeerId == nil))
|
||||
index += 1
|
||||
}
|
||||
} else {
|
||||
entries.append(.publicLinkAvailability(presentationData.theme, presentationData.strings.Group_Username_CreatePublicLinkHelp, true))
|
||||
if case .revokeNames = mode {
|
||||
let count = Int32(publicChannelsToRevoke?.count ?? 0)
|
||||
entries.append(.linksLimitInfo(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesOrExtendInfo("\(premiumLimits.maxPublicLinksCount)").string, count, limits.maxPublicLinksCount, premiumLimits.maxPublicLinksCount, isPremiumDisabled))
|
||||
|
||||
if let publicChannelsToRevoke = publicChannelsToRevoke {
|
||||
var index: Int32 = 0
|
||||
for peer in publicChannelsToRevoke.sorted(by: { lhs, rhs in
|
||||
var lhsDate: Int32 = 0
|
||||
var rhsDate: Int32 = 0
|
||||
if let lhs = lhs as? TelegramChannel {
|
||||
lhsDate = lhs.creationDate
|
||||
}
|
||||
} else {
|
||||
if let rhs = rhs as? TelegramChannel {
|
||||
rhsDate = rhs.creationDate
|
||||
}
|
||||
return lhsDate > rhsDate
|
||||
}) {
|
||||
entries.append(.existingLinkPeerItem(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, peer, ItemListPeerItemEditing(editable: true, editing: true, revealed: state.revealedRevokePeerId == peer.id), state.revokingPeerId == nil))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch selectedType {
|
||||
case .publicChannel:
|
||||
entries.append(.editablePublicLink(presentationData.theme, presentationData.strings, presentationData.strings.Group_PublicLink_Placeholder, currentAddressName))
|
||||
if let status = state.addressNameValidationStatus {
|
||||
let text: String
|
||||
@ -804,7 +805,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
||||
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Group_PublicLink_Info))
|
||||
} else {
|
||||
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePublicLinkHelp))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Channel_Username_CreatePublicLinkHelp))
|
||||
}
|
||||
@ -815,199 +816,203 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
||||
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
|
||||
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
|
||||
}
|
||||
}
|
||||
case .privateChannel:
|
||||
let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation
|
||||
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_InviteLink.uppercased()))
|
||||
entries.append(.privateLink(presentationData.theme, invite, importers?.importers.prefix(3).compactMap { $0.peer.peer.flatMap(EnginePeer.init) } ?? [], importers?.count ?? 0, mode != .initialSetup))
|
||||
if isGroup {
|
||||
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePrivateLinkHelp))
|
||||
} else {
|
||||
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Channel_Username_CreatePrivateLinkHelp))
|
||||
}
|
||||
switch mode {
|
||||
case .initialSetup, .revokeNames:
|
||||
break
|
||||
case .generic, .privateLink:
|
||||
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
|
||||
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
|
||||
}
|
||||
}
|
||||
|
||||
var isDiscussion = false
|
||||
if let cachedData = view.cachedData as? CachedChannelData, case .known = cachedData.linkedDiscussionPeerId {
|
||||
isDiscussion = true
|
||||
}
|
||||
|
||||
if isGroup && (selectedType == .publicChannel || isDiscussion) {
|
||||
if isDiscussion {
|
||||
entries.append(.joinToSendHeader(presentationData.theme, presentationData.strings.Group_Setup_WhoCanSendMessages_Title.uppercased()))
|
||||
entries.append(.joinToSendEveryone(presentationData.theme, presentationData.strings.Group_Setup_WhoCanSendMessages_Everyone, joinToSend == .everyone))
|
||||
entries.append(.joinToSendMembers(presentationData.theme, presentationData.strings.Group_Setup_WhoCanSendMessages_OnlyMembers, joinToSend == .members))
|
||||
}
|
||||
|
||||
if !isDiscussion || joinToSend == .members {
|
||||
entries.append(.approveMembers(presentationData.theme, presentationData.strings.Group_Setup_ApproveNewMembers, approveMembers))
|
||||
entries.append(.approveMembersInfo(presentationData.theme, presentationData.strings.Group_Setup_ApproveNewMembersInfo))
|
||||
}
|
||||
}
|
||||
|
||||
entries.append(.forwardingHeader(presentationData.theme, isGroup ? presentationData.strings.Group_Setup_ForwardingGroupTitle.uppercased() : presentationData.strings.Group_Setup_ForwardingChannelTitle.uppercased()))
|
||||
entries.append(.forwardingDisabled(presentationData.theme, presentationData.strings.Group_Setup_ForwardingDisabled, !forwardingEnabled))
|
||||
entries.append(.forwardingInfo(presentationData.theme, forwardingEnabled ? (isGroup ? presentationData.strings.Group_Setup_ForwardingGroupInfo : presentationData.strings.Group_Setup_ForwardingChannelInfo) : (isGroup ? presentationData.strings.Group_Setup_ForwardingGroupInfoDisabled : presentationData.strings.Group_Setup_ForwardingChannelInfoDisabled)))
|
||||
} else if let peer = view.peers[view.peerId] as? TelegramGroup {
|
||||
switch mode {
|
||||
case .revokeNames:
|
||||
if let publicChannelsToRevoke = publicChannelsToRevoke {
|
||||
// entries.append(.linksLimitInfo(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesOrExtendInfo("\(20)").string, limits.maxPublicLinksCount, premiumLimits.maxPublicLinksCount))
|
||||
|
||||
entries.append(.publicLinkAvailability(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesInfo, false))
|
||||
var index: Int32 = 0
|
||||
for peer in publicChannelsToRevoke.sorted(by: { lhs, rhs in
|
||||
var lhsDate: Int32 = 0
|
||||
var rhsDate: Int32 = 0
|
||||
if let lhs = lhs as? TelegramChannel {
|
||||
lhsDate = lhs.creationDate
|
||||
}
|
||||
if let rhs = rhs as? TelegramChannel {
|
||||
rhsDate = rhs.creationDate
|
||||
}
|
||||
return lhsDate > rhsDate
|
||||
}) {
|
||||
entries.append(.existingLinkPeerItem(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, peer, ItemListPeerItemEditing(editable: true, editing: true, revealed: state.revealedRevokePeerId == peer.id), state.revokingPeerId == nil))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
case .privateLink:
|
||||
let invite = (view.cachedData as? CachedGroupData)?.exportedInvitation
|
||||
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_InviteLink.uppercased()))
|
||||
entries.append(.privateLink(presentationData.theme, invite, importers?.importers.prefix(3).compactMap { $0.peer.peer.flatMap(EnginePeer.init) } ?? [], importers?.count ?? 0, mode != .initialSetup))
|
||||
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.GroupInfo_InviteLink_Help))
|
||||
switch mode {
|
||||
case .initialSetup, .revokeNames:
|
||||
break
|
||||
case .generic, .privateLink:
|
||||
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
|
||||
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
|
||||
}
|
||||
case .generic, .initialSetup:
|
||||
let selectedType: CurrentChannelType
|
||||
if let current = state.selectedType {
|
||||
selectedType = current
|
||||
} else {
|
||||
selectedType = .privateChannel
|
||||
}
|
||||
|
||||
let currentAddressName: String
|
||||
if let current = state.editingPublicLinkText {
|
||||
currentAddressName = current
|
||||
} else {
|
||||
currentAddressName = ""
|
||||
}
|
||||
|
||||
entries.append(.typeHeader(presentationData.theme, presentationData.strings.Group_Setup_TypeHeader.uppercased()))
|
||||
entries.append(.typePublic(presentationData.theme, presentationData.strings.Channel_Setup_TypePublic, selectedType == .publicChannel))
|
||||
entries.append(.typePrivate(presentationData.theme, presentationData.strings.Channel_Setup_TypePrivate, selectedType == .privateChannel))
|
||||
|
||||
switch selectedType {
|
||||
case .publicChannel:
|
||||
entries.append(.typeInfo(presentationData.theme, presentationData.strings.Group_Setup_TypePublicHelp))
|
||||
case .privateChannel:
|
||||
entries.append(.typeInfo(presentationData.theme, presentationData.strings.Group_Setup_TypePrivateHelp))
|
||||
}
|
||||
|
||||
switch selectedType {
|
||||
case .publicChannel:
|
||||
let displayAvailability = publicChannelsToRevoke == nil || !(publicChannelsToRevoke!.isEmpty)
|
||||
let invite = (view.cachedData as? CachedChannelData)?.exportedInvitation
|
||||
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_InviteLink.uppercased()))
|
||||
entries.append(.privateLink(presentationData.theme, invite, importers?.importers.prefix(3).compactMap { $0.peer.peer.flatMap(EnginePeer.init) } ?? [], importers?.count ?? 0, !isInitialSetup))
|
||||
if isGroup {
|
||||
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePrivateLinkHelp))
|
||||
} else {
|
||||
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Channel_Username_CreatePrivateLinkHelp))
|
||||
}
|
||||
switch mode {
|
||||
case .initialSetup, .revokeNames:
|
||||
break
|
||||
case .generic, .privateLink:
|
||||
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
|
||||
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
|
||||
}
|
||||
}
|
||||
|
||||
if displayAvailability {
|
||||
if let publicChannelsToRevoke = publicChannelsToRevoke {
|
||||
// entries.append(.linksLimitInfo(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesOrExtendInfo("\(20)").string, limits.maxPublicLinksCount, premiumLimits.maxPublicLinksCount))
|
||||
|
||||
entries.append(.publicLinkAvailability(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesInfo, false))
|
||||
var index: Int32 = 0
|
||||
for peer in publicChannelsToRevoke.sorted(by: { lhs, rhs in
|
||||
var lhsDate: Int32 = 0
|
||||
var rhsDate: Int32 = 0
|
||||
if let lhs = lhs as? TelegramChannel {
|
||||
lhsDate = lhs.creationDate
|
||||
var isDiscussion = false
|
||||
if let cachedData = view.cachedData as? CachedChannelData, case .known = cachedData.linkedDiscussionPeerId {
|
||||
isDiscussion = true
|
||||
}
|
||||
|
||||
if isGroup && (selectedType == .publicChannel || isDiscussion) {
|
||||
if isDiscussion {
|
||||
entries.append(.joinToSendHeader(presentationData.theme, presentationData.strings.Group_Setup_WhoCanSendMessages_Title.uppercased()))
|
||||
entries.append(.joinToSendEveryone(presentationData.theme, presentationData.strings.Group_Setup_WhoCanSendMessages_Everyone, joinToSend == .everyone))
|
||||
entries.append(.joinToSendMembers(presentationData.theme, presentationData.strings.Group_Setup_WhoCanSendMessages_OnlyMembers, joinToSend == .members))
|
||||
}
|
||||
|
||||
if !isDiscussion || joinToSend == .members {
|
||||
entries.append(.approveMembers(presentationData.theme, presentationData.strings.Group_Setup_ApproveNewMembers, approveMembers))
|
||||
entries.append(.approveMembersInfo(presentationData.theme, presentationData.strings.Group_Setup_ApproveNewMembersInfo))
|
||||
}
|
||||
}
|
||||
|
||||
entries.append(.forwardingHeader(presentationData.theme, isGroup ? presentationData.strings.Group_Setup_ForwardingGroupTitle.uppercased() : presentationData.strings.Group_Setup_ForwardingChannelTitle.uppercased()))
|
||||
entries.append(.forwardingDisabled(presentationData.theme, presentationData.strings.Group_Setup_ForwardingDisabled, !forwardingEnabled))
|
||||
entries.append(.forwardingInfo(presentationData.theme, forwardingEnabled ? (isGroup ? presentationData.strings.Group_Setup_ForwardingGroupInfo : presentationData.strings.Group_Setup_ForwardingChannelInfo) : (isGroup ? presentationData.strings.Group_Setup_ForwardingGroupInfoDisabled : presentationData.strings.Group_Setup_ForwardingChannelInfoDisabled)))
|
||||
}
|
||||
} else if let peer = view.peers[view.peerId] as? TelegramGroup {
|
||||
if case .revokeNames = mode {
|
||||
let count = Int32(publicChannelsToRevoke?.count ?? 0)
|
||||
entries.append(.linksLimitInfo(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesOrExtendInfo("\(premiumLimits.maxPublicLinksCount)").string, count, limits.maxPublicLinksCount, premiumLimits.maxPublicLinksCount, isPremiumDisabled))
|
||||
|
||||
if let publicChannelsToRevoke = publicChannelsToRevoke {
|
||||
var index: Int32 = 0
|
||||
for peer in publicChannelsToRevoke.sorted(by: { lhs, rhs in
|
||||
var lhsDate: Int32 = 0
|
||||
var rhsDate: Int32 = 0
|
||||
if let lhs = lhs as? TelegramChannel {
|
||||
lhsDate = lhs.creationDate
|
||||
}
|
||||
if let rhs = rhs as? TelegramChannel {
|
||||
rhsDate = rhs.creationDate
|
||||
}
|
||||
return lhsDate > rhsDate
|
||||
}) {
|
||||
entries.append(.existingLinkPeerItem(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, peer, ItemListPeerItemEditing(editable: true, editing: true, revealed: state.revealedRevokePeerId == peer.id), state.revokingPeerId == nil))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch mode {
|
||||
case .revokeNames:
|
||||
break
|
||||
case .privateLink:
|
||||
let invite = (view.cachedData as? CachedGroupData)?.exportedInvitation
|
||||
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_InviteLink.uppercased()))
|
||||
entries.append(.privateLink(presentationData.theme, invite, importers?.importers.prefix(3).compactMap { $0.peer.peer.flatMap(EnginePeer.init) } ?? [], importers?.count ?? 0, !isInitialSetup))
|
||||
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.GroupInfo_InviteLink_Help))
|
||||
switch mode {
|
||||
case .initialSetup, .revokeNames:
|
||||
break
|
||||
case .generic, .privateLink:
|
||||
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
|
||||
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
|
||||
}
|
||||
case .generic, .initialSetup:
|
||||
let selectedType: CurrentChannelType
|
||||
if let current = state.selectedType {
|
||||
selectedType = current
|
||||
} else {
|
||||
selectedType = .privateChannel
|
||||
}
|
||||
|
||||
let currentAddressName: String
|
||||
if let current = state.editingPublicLinkText {
|
||||
currentAddressName = current
|
||||
} else {
|
||||
currentAddressName = ""
|
||||
}
|
||||
|
||||
entries.append(.typeHeader(presentationData.theme, presentationData.strings.Group_Setup_TypeHeader.uppercased()))
|
||||
entries.append(.typePublic(presentationData.theme, presentationData.strings.Channel_Setup_TypePublic, selectedType == .publicChannel))
|
||||
entries.append(.typePrivate(presentationData.theme, presentationData.strings.Channel_Setup_TypePrivate, selectedType == .privateChannel))
|
||||
|
||||
switch selectedType {
|
||||
case .publicChannel:
|
||||
entries.append(.typeInfo(presentationData.theme, presentationData.strings.Group_Setup_TypePublicHelp))
|
||||
case .privateChannel:
|
||||
entries.append(.typeInfo(presentationData.theme, presentationData.strings.Group_Setup_TypePrivateHelp))
|
||||
}
|
||||
|
||||
switch selectedType {
|
||||
case .publicChannel:
|
||||
let displayAvailability = publicChannelsToRevoke == nil || !(publicChannelsToRevoke!.isEmpty)
|
||||
|
||||
if displayAvailability {
|
||||
if let publicChannelsToRevoke = publicChannelsToRevoke {
|
||||
// entries.append(.linksLimitInfo(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesOrExtendInfo("\(20)").string, limits.maxPublicLinksCount, premiumLimits.maxPublicLinksCount))
|
||||
|
||||
entries.append(.publicLinkAvailability(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesInfo, false))
|
||||
var index: Int32 = 0
|
||||
for peer in publicChannelsToRevoke.sorted(by: { lhs, rhs in
|
||||
var lhsDate: Int32 = 0
|
||||
var rhsDate: Int32 = 0
|
||||
if let lhs = lhs as? TelegramChannel {
|
||||
lhsDate = lhs.creationDate
|
||||
}
|
||||
if let rhs = rhs as? TelegramChannel {
|
||||
rhsDate = rhs.creationDate
|
||||
}
|
||||
return lhsDate > rhsDate
|
||||
}) {
|
||||
entries.append(.existingLinkPeerItem(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, peer, ItemListPeerItemEditing(editable: true, editing: true, revealed: state.revealedRevokePeerId == peer.id), state.revokingPeerId == nil))
|
||||
index += 1
|
||||
}
|
||||
if let rhs = rhs as? TelegramChannel {
|
||||
rhsDate = rhs.creationDate
|
||||
}
|
||||
return lhsDate > rhsDate
|
||||
}) {
|
||||
entries.append(.existingLinkPeerItem(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, peer, ItemListPeerItemEditing(editable: true, editing: true, revealed: state.revealedRevokePeerId == peer.id), state.revokingPeerId == nil))
|
||||
index += 1
|
||||
} else {
|
||||
entries.append(.publicLinkAvailability(presentationData.theme, presentationData.strings.Group_Username_CreatePublicLinkHelp, true))
|
||||
}
|
||||
} else {
|
||||
entries.append(.publicLinkAvailability(presentationData.theme, presentationData.strings.Group_Username_CreatePublicLinkHelp, true))
|
||||
}
|
||||
} else {
|
||||
entries.append(.editablePublicLink(presentationData.theme, presentationData.strings, "", currentAddressName))
|
||||
if let status = state.addressNameValidationStatus {
|
||||
let text: String
|
||||
switch status {
|
||||
case let .invalidFormat(error):
|
||||
switch error {
|
||||
case .startsWithDigit:
|
||||
text = presentationData.strings.Group_Username_InvalidStartsWithNumber
|
||||
case .startsWithUnderscore:
|
||||
text = presentationData.strings.Channel_Username_InvalidStartsWithUnderscore
|
||||
case .endsWithUnderscore:
|
||||
text = presentationData.strings.Channel_Username_InvalidEndsWithUnderscore
|
||||
case .tooShort:
|
||||
text = presentationData.strings.Group_Username_InvalidTooShort
|
||||
case .invalidCharacters:
|
||||
entries.append(.editablePublicLink(presentationData.theme, presentationData.strings, "", currentAddressName))
|
||||
if let status = state.addressNameValidationStatus {
|
||||
let text: String
|
||||
switch status {
|
||||
case let .invalidFormat(error):
|
||||
switch error {
|
||||
case .startsWithDigit:
|
||||
text = presentationData.strings.Group_Username_InvalidStartsWithNumber
|
||||
case .startsWithUnderscore:
|
||||
text = presentationData.strings.Channel_Username_InvalidStartsWithUnderscore
|
||||
case .endsWithUnderscore:
|
||||
text = presentationData.strings.Channel_Username_InvalidEndsWithUnderscore
|
||||
case .tooShort:
|
||||
text = presentationData.strings.Group_Username_InvalidTooShort
|
||||
case .invalidCharacters:
|
||||
text = presentationData.strings.Channel_Username_InvalidCharacters
|
||||
}
|
||||
case let .availability(availability):
|
||||
switch availability {
|
||||
case .available:
|
||||
text = presentationData.strings.Channel_Username_UsernameIsAvailable(currentAddressName).string
|
||||
case .invalid:
|
||||
text = presentationData.strings.Channel_Username_InvalidCharacters
|
||||
case .taken:
|
||||
text = presentationData.strings.Channel_Username_InvalidTaken
|
||||
}
|
||||
case let .availability(availability):
|
||||
switch availability {
|
||||
case .available:
|
||||
text = presentationData.strings.Channel_Username_UsernameIsAvailable(currentAddressName).string
|
||||
case .invalid:
|
||||
text = presentationData.strings.Channel_Username_InvalidCharacters
|
||||
case .taken:
|
||||
text = presentationData.strings.Channel_Username_InvalidTaken
|
||||
case .checking:
|
||||
text = presentationData.strings.Channel_Username_CheckingUsername
|
||||
}
|
||||
case .checking:
|
||||
text = presentationData.strings.Channel_Username_CheckingUsername
|
||||
|
||||
entries.append(.publicLinkStatus(presentationData.theme, text, status))
|
||||
}
|
||||
|
||||
entries.append(.publicLinkStatus(presentationData.theme, text, status))
|
||||
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePublicLinkHelp))
|
||||
}
|
||||
|
||||
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePublicLinkHelp))
|
||||
}
|
||||
case .privateChannel:
|
||||
let invite = (view.cachedData as? CachedGroupData)?.exportedInvitation
|
||||
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_InviteLink.uppercased()))
|
||||
entries.append(.privateLink(presentationData.theme, invite, importers?.importers.prefix(3).compactMap { $0.peer.peer.flatMap(EnginePeer.init) } ?? [], importers?.count ?? 0, mode != .initialSetup))
|
||||
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePrivateLinkHelp))
|
||||
switch mode {
|
||||
case .initialSetup, .revokeNames:
|
||||
break
|
||||
case .generic, .privateLink:
|
||||
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
|
||||
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
|
||||
}
|
||||
case .privateChannel:
|
||||
let invite = (view.cachedData as? CachedGroupData)?.exportedInvitation
|
||||
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_InviteLink.uppercased()))
|
||||
entries.append(.privateLink(presentationData.theme, invite, importers?.importers.prefix(3).compactMap { $0.peer.peer.flatMap(EnginePeer.init) } ?? [], importers?.count ?? 0, !isInitialSetup))
|
||||
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePrivateLinkHelp))
|
||||
switch mode {
|
||||
case .initialSetup, .revokeNames:
|
||||
break
|
||||
case .generic, .privateLink:
|
||||
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
|
||||
entries.append(.privateLinkManageInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let forwardingEnabled: Bool
|
||||
if let enabled = state.forwardingEnabled {
|
||||
forwardingEnabled = enabled
|
||||
} else {
|
||||
if peer.flags.contains(.copyProtectionEnabled) {
|
||||
forwardingEnabled = false
|
||||
|
||||
let forwardingEnabled: Bool
|
||||
if let enabled = state.forwardingEnabled {
|
||||
forwardingEnabled = enabled
|
||||
} else {
|
||||
forwardingEnabled = true
|
||||
if peer.flags.contains(.copyProtectionEnabled) {
|
||||
forwardingEnabled = false
|
||||
} else {
|
||||
forwardingEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
entries.append(.forwardingHeader(presentationData.theme, presentationData.strings.Group_Setup_ForwardingGroupTitle.uppercased()))
|
||||
entries.append(.forwardingDisabled(presentationData.theme, presentationData.strings.Group_Setup_ForwardingDisabled, !forwardingEnabled))
|
||||
entries.append(.forwardingInfo(presentationData.theme, forwardingEnabled ? presentationData.strings.Group_Setup_ForwardingGroupInfo : presentationData.strings.Group_Setup_ForwardingGroupInfoDisabled))
|
||||
}
|
||||
|
||||
entries.append(.forwardingHeader(presentationData.theme, presentationData.strings.Group_Setup_ForwardingGroupTitle.uppercased()))
|
||||
entries.append(.forwardingDisabled(presentationData.theme, presentationData.strings.Group_Setup_ForwardingDisabled, !forwardingEnabled))
|
||||
entries.append(.forwardingInfo(presentationData.theme, forwardingEnabled ? presentationData.strings.Group_Setup_ForwardingGroupInfo : presentationData.strings.Group_Setup_ForwardingGroupInfoDisabled))
|
||||
}
|
||||
|
||||
return entries
|
||||
@ -1079,16 +1084,24 @@ public enum ChannelVisibilityControllerMode {
|
||||
case initialSetup
|
||||
case generic
|
||||
case privateLink
|
||||
case revokeNames
|
||||
case revokeNames([Peer])
|
||||
}
|
||||
|
||||
public func channelVisibilityController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: PeerId, mode: ChannelVisibilityControllerMode, upgradedToSupergroup: @escaping (PeerId, @escaping () -> Void) -> Void, onDismissRemoveController: ViewController? = nil) -> ViewController {
|
||||
public func channelVisibilityController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: PeerId, mode: ChannelVisibilityControllerMode, upgradedToSupergroup: @escaping (PeerId, @escaping () -> Void) -> Void, onDismissRemoveController: ViewController? = nil, revokedPeerAddressName: ((PeerId) -> Void)? = nil) -> ViewController {
|
||||
let statePromise = ValuePromise(ChannelVisibilityControllerState(), ignoreRepeated: true)
|
||||
let stateValue = Atomic(value: ChannelVisibilityControllerState())
|
||||
let updateState: ((ChannelVisibilityControllerState) -> ChannelVisibilityControllerState) -> Void = { f in
|
||||
statePromise.set(stateValue.modify { f($0) })
|
||||
}
|
||||
|
||||
let adminedPublicChannels = Promise<[Peer]?>()
|
||||
if case let .revokeNames(peers) = mode {
|
||||
adminedPublicChannels.set(.single(peers))
|
||||
} else {
|
||||
adminedPublicChannels.set(context.engine.peers.adminedPublicChannels(scope: .all)
|
||||
|> map(Optional.init))
|
||||
}
|
||||
|
||||
let peersDisablingAddressNameAssignment = Promise<[Peer]?>()
|
||||
peersDisablingAddressNameAssignment.set(.single(nil) |> then(context.engine.peers.channelAddressNameAssignmentAvailability(peerId: peerId.namespace == Namespaces.Peer.CloudChannel ? peerId : nil) |> mapToSignal { result -> Signal<[Peer]?, NoError> in
|
||||
if case .addressNameLimitReached = result {
|
||||
@ -1133,8 +1146,42 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
actionsDisposable.add(toggleRequestToJoinDisposable)
|
||||
|
||||
let arguments = ChannelVisibilityControllerArguments(context: context, updateCurrentType: { type in
|
||||
updateState { state in
|
||||
return state.withUpdatedSelectedType(type)
|
||||
if type == .publicChannel {
|
||||
let _ = combineLatest(
|
||||
queue: Queue.mainQueue(),
|
||||
adminedPublicChannels.get() |> filter { $0 != nil } |> take(1),
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)),
|
||||
context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: false),
|
||||
TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: true)
|
||||
)
|
||||
).start(next: { peers, accountPeer, data in
|
||||
let (limits, premiumLimits) = data
|
||||
let isPremium = accountPeer?.isPremium ?? false
|
||||
|
||||
if let peers = peers {
|
||||
let count = Int32(peers.count)
|
||||
if count < limits.maxPublicLinksCount || (count < premiumLimits.maxPublicLinksCount && isPremium) {
|
||||
updateState { state in
|
||||
return state.withUpdatedSelectedType(type)
|
||||
}
|
||||
} else {
|
||||
let controller = channelVisibilityController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, mode: .revokeNames(peers), upgradedToSupergroup: { _, _ in }, revokedPeerAddressName: { revokedPeerId in
|
||||
let updatedPublicChannels = peers.filter { $0.id != revokedPeerId }
|
||||
adminedPublicChannels.set(.single(updatedPublicChannels) |> then(
|
||||
context.engine.peers.adminedPublicChannels(scope: .all) |> map(Optional.init))
|
||||
)
|
||||
})
|
||||
controller.navigationPresentation = .modal
|
||||
pushControllerImpl?(controller)
|
||||
}
|
||||
} else {
|
||||
}
|
||||
})
|
||||
} else {
|
||||
updateState { state in
|
||||
return state.withUpdatedSelectedType(type)
|
||||
}
|
||||
}
|
||||
}, updatePublicLinkText: { currentText, text in
|
||||
if text.isEmpty {
|
||||
@ -1179,11 +1226,8 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
return state.withUpdatedRevokingPeerId(nil)
|
||||
}
|
||||
}, completed: {
|
||||
peersDisablingAddressNameAssignment.set(.single([]) |> delay(0.2, queue: Queue.mainQueue()) |> afterNext { _ in
|
||||
updateState { state in
|
||||
return state.withUpdatedRevokingPeerId(nil)
|
||||
}
|
||||
})
|
||||
revokedPeerAddressName?(peerId)
|
||||
dismissImpl?()
|
||||
}))
|
||||
}, copyLink: { invite in
|
||||
UIPasteboard.general.string = invite.link
|
||||
@ -1353,7 +1397,7 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
presentationData,
|
||||
statePromise.get() |> deliverOnMainQueue,
|
||||
peerView,
|
||||
peersDisablingAddressNameAssignment.get() |> deliverOnMainQueue,
|
||||
adminedPublicChannels.get(),
|
||||
importersContext,
|
||||
importersState.get(),
|
||||
context.engine.data.get(
|
||||
@ -1373,7 +1417,10 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
|
||||
var rightNavigationButton: ItemListNavigationButton?
|
||||
if case .revokeNames = mode {
|
||||
|
||||
footerItem = IncreaseLimitFooterItem(theme: presentationData.theme, title: presentationData.strings.Premium_IncreaseLimit, colorful: true, action: {
|
||||
let controller = PremiumIntroScreen(context: context, source: .publicLinks)
|
||||
pushControllerImpl?(controller)
|
||||
})
|
||||
} else {
|
||||
if let peer = peer as? TelegramChannel {
|
||||
var doneEnabled = true
|
||||
@ -1400,7 +1447,14 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
}
|
||||
}
|
||||
|
||||
rightNavigationButton = ItemListNavigationButton(content: .text(mode == .initialSetup ? presentationData.strings.Common_Next : presentationData.strings.Common_Done), style: state.updatingAddressName ? .activity : .bold, enabled: doneEnabled, action: {
|
||||
let isInitialSetup: Bool
|
||||
if case .initialSetup = mode {
|
||||
isInitialSetup = true
|
||||
} else {
|
||||
isInitialSetup = false
|
||||
}
|
||||
|
||||
rightNavigationButton = ItemListNavigationButton(content: .text(isInitialSetup ? presentationData.strings.Common_Next : presentationData.strings.Common_Done), style: state.updatingAddressName ? .activity : .bold, enabled: doneEnabled, action: {
|
||||
var updatedAddressNameValue: String?
|
||||
updateState { state in
|
||||
updatedAddressNameValue = updatedAddressName(mode: mode, state: state, peer: peer, cachedData: view.cachedData)
|
||||
@ -1618,14 +1672,7 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
if selectedType == .publicChannel, let hadNamesToRevoke = hadNamesToRevoke, !crossfade {
|
||||
crossfade = hadNamesToRevoke != hasNamesToRevoke
|
||||
}
|
||||
|
||||
if hasNamesToRevoke && selectedType == .publicChannel {
|
||||
footerItem = IncreaseLimitFooterItem(theme: presentationData.theme, title: presentationData.strings.Premium_IncreaseLimit, colorful: true, action: {
|
||||
let controller = PremiumIntroScreen(context: context, source: .publicLinks)
|
||||
pushControllerImpl?(controller)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
if let hadNamesToRevoke = hadNamesToRevoke {
|
||||
animateChanges = hadNamesToRevoke != hasNamesToRevoke
|
||||
}
|
||||
@ -1645,7 +1692,8 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
||||
title = presentationData.strings.Premium_LimitReached
|
||||
}
|
||||
|
||||
let entries = channelVisibilityControllerEntries(presentationData: presentationData, mode: mode, view: view, publicChannelsToRevoke: publicChannelsToRevoke, importers: importers, state: state, limits: limits, premiumLimits: premiumLimits, isPremium: isPremium)
|
||||
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
|
||||
let entries = channelVisibilityControllerEntries(presentationData: presentationData, mode: mode, view: view, publicChannelsToRevoke: publicChannelsToRevoke, importers: importers, state: state, limits: limits, premiumLimits: premiumLimits, isPremium: isPremium, isPremiumDisabled: premiumConfiguration.isPremiumDisabled)
|
||||
|
||||
var focusItemTag: ItemListItemTag?
|
||||
if entries.count > 1, let cachedChannelData = view.cachedData as? CachedChannelData, cachedChannelData.peerGeoLocation != nil {
|
||||
|
@ -81,6 +81,9 @@ private let boldTextFont = Font.semibold(15.0)
|
||||
|
||||
class IncreaseLimitHeaderItemNode: ListViewItemNode {
|
||||
private var hostView: ComponentHostView<Empty>?
|
||||
|
||||
private var params: (AnyComponent<Empty>, CGSize, ListViewItemNodeLayout, CGSize)?
|
||||
|
||||
private let titleNode: TextNode
|
||||
private let textNode: TextNode
|
||||
|
||||
@ -109,6 +112,19 @@ class IncreaseLimitHeaderItemNode: ListViewItemNode {
|
||||
let hostView = ComponentHostView<Empty>()
|
||||
self.hostView = hostView
|
||||
self.view.addSubview(hostView)
|
||||
|
||||
if let (component, containerSize, layout, textSize) = self.params {
|
||||
let size = hostView.update(
|
||||
transition: .immediate,
|
||||
component: component,
|
||||
environment: {},
|
||||
containerSize: containerSize
|
||||
)
|
||||
hostView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - size.width) / 2.0), y: -30.0), size: size)
|
||||
|
||||
let textSpacing: CGFloat = -6.0
|
||||
self.textNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - textSize.width) / 2.0), y: size.height + textSpacing), size: textSize)
|
||||
}
|
||||
}
|
||||
|
||||
func asyncLayout() -> (_ item: IncreaseLimitHeaderItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
||||
@ -161,31 +177,36 @@ class IncreaseLimitHeaderItemNode: ListViewItemNode {
|
||||
]
|
||||
}
|
||||
|
||||
let component = AnyComponent(PremiumLimitDisplayComponent(
|
||||
inactiveColor: item.theme.list.itemBlocksSeparatorColor.withAlphaComponent(0.5),
|
||||
activeColors: gradientColors,
|
||||
inactiveTitle: item.strings.Premium_Free,
|
||||
inactiveValue: item.count > item.limit ? "\(item.limit)" : "",
|
||||
inactiveTitleColor: item.theme.list.itemPrimaryTextColor,
|
||||
activeTitle: item.strings.Premium_Premium,
|
||||
activeValue: item.count >= item.premiumCount ? "" : "\(item.premiumCount)",
|
||||
activeTitleColor: .white,
|
||||
badgeIconName: badgeIconName,
|
||||
badgeText: "\(item.count)",
|
||||
badgePosition: CGFloat(item.count) / CGFloat(item.premiumCount),
|
||||
isPremiumDisabled: item.isPremiumDisabled
|
||||
))
|
||||
let containerSize = CGSize(width: layout.size.width - params.leftInset - params.rightInset, height: 200.0)
|
||||
|
||||
let _ = textApply()
|
||||
|
||||
if let hostView = strongSelf.hostView {
|
||||
let size = hostView.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(PremiumLimitDisplayComponent(
|
||||
inactiveColor: item.theme.list.itemBlocksSeparatorColor.withAlphaComponent(0.5),
|
||||
activeColors: gradientColors,
|
||||
inactiveTitle: item.strings.Premium_Free,
|
||||
inactiveValue: item.count > item.limit ? "\(item.limit)" : "",
|
||||
inactiveTitleColor: item.theme.list.itemPrimaryTextColor,
|
||||
activeTitle: item.strings.Premium_Premium,
|
||||
activeValue: item.count >= item.premiumCount ? "" : "\(item.premiumCount)",
|
||||
activeTitleColor: .white,
|
||||
badgeIconName: badgeIconName,
|
||||
badgeText: "\(item.count)",
|
||||
badgePosition: CGFloat(item.count) / CGFloat(item.premiumCount),
|
||||
isPremiumDisabled: item.isPremiumDisabled
|
||||
)),
|
||||
component: component,
|
||||
environment: {},
|
||||
containerSize: CGSize(width: layout.size.width - params.leftInset - params.rightInset, height: 200.0)
|
||||
containerSize: containerSize
|
||||
)
|
||||
hostView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - size.width) / 2.0), y: -30.0), size: size)
|
||||
|
||||
let _ = textApply()
|
||||
strongSelf.textNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - textLayout.size.width) / 2.0), y: size.height + textSpacing), size: textLayout.size)
|
||||
}
|
||||
|
||||
strongSelf.params = (component, containerSize, layout, textLayout.size)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -807,7 +807,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
|
||||
super.init()
|
||||
|
||||
self.disposable = (context.engine.data.get(
|
||||
self.disposable = (context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Configuration.App(),
|
||||
TelegramEngine.EngineData.Item.Configuration.PremiumPromo()
|
||||
)
|
||||
@ -841,6 +841,8 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
}
|
||||
})
|
||||
|
||||
let _ = updatePremiumPromoConfigurationOnce(account: context.account).start()
|
||||
|
||||
let stickersKey: PostboxViewKey = .orderedItemList(id: Namespaces.OrderedItemList.CloudPremiumStickers)
|
||||
self.stickersDisposable = (self.context.account.postbox.combinedView(keys: [stickersKey])
|
||||
|> deliverOnMainQueue).start(next: { [weak self] views in
|
||||
@ -1362,9 +1364,9 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
self.disposable = combineLatest(
|
||||
queue: Queue.mainQueue(),
|
||||
availableProducts,
|
||||
context.account.postbox.peerView(id: context.account.peerId)
|
||||
|> map { view -> Bool in
|
||||
return view.peers[view.peerId]?.isPremium ?? false
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||
|> map { peer -> Bool in
|
||||
return peer?.isPremium ?? false
|
||||
},
|
||||
otherPeerName
|
||||
).start(next: { [weak self] products, isPremium, otherPeerName in
|
||||
@ -1418,6 +1420,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
|
||||
}, completed: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
let _ = updatePremiumPromoConfigurationOnce(account: strongSelf.context.account).start()
|
||||
strongSelf.isPremium = true
|
||||
strongSelf.updated(transition: .easeInOut(duration: 0.25))
|
||||
strongSelf.completion()
|
||||
|
@ -49,7 +49,7 @@ final class ReactionsCarouselComponent: Component {
|
||||
public func update(component: ReactionsCarouselComponent, availableSize: CGSize, environment: Environment<DemoPageEnvironment>, transition: Transition) -> CGSize {
|
||||
let isDisplaying = environment[DemoPageEnvironment.self].isDisplaying
|
||||
|
||||
if self.node == nil {
|
||||
if self.node == nil && !component.reactions.isEmpty {
|
||||
let node = ReactionCarouselNode(
|
||||
context: component.context,
|
||||
theme: component.theme,
|
||||
|
@ -45,7 +45,7 @@ final class StickersCarouselComponent: Component {
|
||||
public func update(component: StickersCarouselComponent, availableSize: CGSize, environment: Environment<DemoPageEnvironment>, transition: Transition) -> CGSize {
|
||||
let isDisplaying = environment[DemoPageEnvironment.self].isDisplaying
|
||||
|
||||
if self.node == nil {
|
||||
if self.node == nil && !component.stickers.isEmpty {
|
||||
let node = StickersCarouselNode(
|
||||
context: component.context,
|
||||
stickers: component.stickers
|
||||
|
@ -6227,11 +6227,13 @@ public extension Api.functions.messages {
|
||||
}
|
||||
}
|
||||
public extension Api.functions.payments {
|
||||
static func assignAppStoreTransaction(transactionId: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
static func assignAppStoreTransaction(flags: Int32, transactionId: String, receipt: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(1654235439)
|
||||
buffer.appendInt32(267129798)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeString(transactionId, buffer: buffer, boxed: false)
|
||||
return (FunctionDescription(name: "payments.assignAppStoreTransaction", parameters: [("transactionId", String(describing: transactionId))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
serializeBytes(receipt, buffer: buffer, boxed: false)
|
||||
return (FunctionDescription(name: "payments.assignAppStoreTransaction", parameters: [("flags", String(describing: flags)), ("transactionId", String(describing: transactionId)), ("receipt", String(describing: receipt))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
@ -6381,21 +6383,6 @@ public extension Api.functions.payments {
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.payments {
|
||||
static func restoreAppStoreReceipt(receipt: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-2132923705)
|
||||
serializeBytes(receipt, buffer: buffer, boxed: false)
|
||||
return (FunctionDescription(name: "payments.restoreAppStoreReceipt", parameters: [("receipt", String(describing: receipt))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.Updates
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.payments {
|
||||
static func restorePlayMarketReceipt(receipt: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
|
@ -495,6 +495,8 @@ class VoiceChatFullscreenParticipantItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
let leftInset: CGFloat = 58.0 + params.leftInset
|
||||
|
||||
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: item.context.currentAppConfiguration.with { $0 })
|
||||
|
||||
var titleIconsWidth: CGFloat = 0.0
|
||||
var currentCredibilityIconImage: UIImage?
|
||||
var credibilityIconOffset: CGFloat = 0.0
|
||||
@ -507,6 +509,9 @@ class VoiceChatFullscreenParticipantItemNode: ItemListRevealOptionsItemNode {
|
||||
} else if item.peer.isVerified {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
||||
credibilityIconOffset = 3.0
|
||||
} else if item.peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.premiumIcon(item.presentationData.theme)
|
||||
credibilityIconOffset = 3.0
|
||||
}
|
||||
|
||||
if let currentCredibilityIconImage = currentCredibilityIconImage {
|
||||
|
@ -829,6 +829,8 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
||||
let verticalInset: CGFloat = 8.0
|
||||
let verticalOffset: CGFloat = 0.0
|
||||
|
||||
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: item.context.currentAppConfiguration.with { $0 })
|
||||
|
||||
var titleIconsWidth: CGFloat = 0.0
|
||||
var currentCredibilityIconImage: UIImage?
|
||||
var credibilityIconOffset: CGFloat = 0.0
|
||||
@ -841,6 +843,9 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
||||
} else if item.peer.isVerified {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
||||
credibilityIconOffset = 3.0
|
||||
} else if item.peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.premiumIcon(item.presentationData.theme)
|
||||
credibilityIconOffset = 3.0
|
||||
}
|
||||
|
||||
if let currentCredibilityIconImage = currentCredibilityIconImage {
|
||||
|
@ -8,26 +8,18 @@ public enum AssignAppStoreTransactionError {
|
||||
case generic
|
||||
}
|
||||
|
||||
func _internal_assignAppStoreTransaction(account: Account, transactionId: String) -> Signal<Never, AssignAppStoreTransactionError> {
|
||||
return account.network.request(Api.functions.payments.assignAppStoreTransaction(transactionId: transactionId))
|
||||
func _internal_assignAppStoreTransaction(account: Account, transactionId: String, receipt: Data, restore: Bool) -> Signal<Never, AssignAppStoreTransactionError> {
|
||||
var flags: Int32 = 0
|
||||
if restore {
|
||||
flags |= (1 << 0)
|
||||
}
|
||||
return account.network.request(Api.functions.payments.assignAppStoreTransaction(flags: flags, transactionId: transactionId, receipt: Buffer(data: receipt)))
|
||||
|> mapError { _ -> AssignAppStoreTransactionError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { updates -> Signal<Never, AssignAppStoreTransactionError> in
|
||||
account.stateManager.addUpdates(updates)
|
||||
|
||||
return account.postbox.peerView(id: account.peerId)
|
||||
|> castError(AssignAppStoreTransactionError.self)
|
||||
|> take(until: { view in
|
||||
if let peer = view.peers[view.peerId], peer.isPremium {
|
||||
return SignalTakeAction(passthrough: false, complete: true)
|
||||
} else {
|
||||
return SignalTakeAction(passthrough: false, complete: false)
|
||||
}
|
||||
})
|
||||
|> mapToSignal { _ -> Signal<Never, AssignAppStoreTransactionError> in
|
||||
return .never()
|
||||
}
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Foundation
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
|
||||
@ -37,8 +38,8 @@ public extension TelegramEngine {
|
||||
return _internal_clearBotPaymentInfo(network: self.account.network, info: info)
|
||||
}
|
||||
|
||||
public func assignAppStoreTransaction(transactionId: String) -> Signal<Never, AssignAppStoreTransactionError> {
|
||||
return _internal_assignAppStoreTransaction(account: self.account, transactionId: transactionId)
|
||||
public func assignAppStoreTransaction(transactionId: String, receipt: Data, restore: Bool) -> Signal<Never, AssignAppStoreTransactionError> {
|
||||
return _internal_assignAppStoreTransaction(account: self.account, transactionId: transactionId, receipt: receipt, restore: restore)
|
||||
}
|
||||
|
||||
public func canPurchasePremium() -> Signal<Bool, NoError> {
|
||||
|
@ -2300,6 +2300,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
let themeUpdated = self.presentationData?.theme !== presentationData.theme
|
||||
self.presentationData = presentationData
|
||||
|
||||
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 })
|
||||
|
||||
let credibilityIcon: CredibilityIcon
|
||||
if let peer = peer {
|
||||
if peer.isFake {
|
||||
@ -2308,7 +2310,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
credibilityIcon = .scam
|
||||
} else if peer.isVerified {
|
||||
credibilityIcon = .verified
|
||||
} else if peer.isPremium {
|
||||
} else if peer.isPremium && !premiumConfiguration.isPremiumDisabled {
|
||||
credibilityIcon = .premium
|
||||
} else {
|
||||
credibilityIcon = .none
|
||||
|
Loading…
x
Reference in New Issue
Block a user