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
d17391ad9b
commit
2bf11a6279
@ -12344,6 +12344,7 @@ Sorry for the inconvenience.";
|
||||
"Stars.Transfer.Purchased.Stars_any" = "%@ Stars";
|
||||
"Stars.Transfer.UnlockedText" = "You unlocked media for **%1$@**.";
|
||||
"Stars.Transfer.UnlockInfo" = "Do you want to unlock %1$@ in **%2$@** for **%3$@**?";
|
||||
"Stars.Transfer.UnlockBotInfo" = "Do you want to unlock %1$@ from **%2$@** for **%3$@**?";
|
||||
|
||||
"Stars.Transfer.Balance" = "Balance";
|
||||
|
||||
@ -12695,6 +12696,9 @@ Sorry for the inconvenience.";
|
||||
"Stars.Transaction.Subscription.Cancelled" = "You have cancelled your subscription.";
|
||||
"Stars.Transaction.Subscription.Renew" = "Renew Subscription";
|
||||
"Stars.Transaction.Subscription.Cancel" = "Cancel Subscription";
|
||||
"Stars.Transaction.Subscription.JoinChannel" = "Join Channel";
|
||||
"Stars.Transaction.Subscription.JoinAgainChannel" = "Join Channel";
|
||||
"Stars.Transaction.Subscription.LeftChannel" = "You left channel but you can still get back until %@";
|
||||
"Stars.Transaction.Subscription.PerMonth" = "%@ / month";
|
||||
"Stars.Transaction.Subscription.PerMonthUsd" = "appx. %@ per month";
|
||||
"Stars.Transaction.Subscription.Subscription" = "Subscription";
|
||||
@ -12721,3 +12725,14 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Stars.Intro.Transaction.SubscriptionFee.Title" = "Monthly Subscription Fee";
|
||||
"Stars.Intro.Transaction.Reaction.Title" = "Star Reaction";
|
||||
|
||||
"Stars.Purchase.GenericPurchasePurpose" = "Buy Stars to unlock content and services on Telegram.";
|
||||
"Stars.Purchase.PurchasePurpose.subs" = "Buy Stars to keep all your subscriptions.";
|
||||
|
||||
"Stars.Transfer.Subscribe.Channel.Title" = "Subscribe";
|
||||
"Stars.Transfer.SubscribeInfo" = "Do you want to subscribe to **%1$@** for **%2$@** per month?";
|
||||
"Stars.Transfer.Subscribe" = "Subscribe";
|
||||
"Stars.Transfer.Subscribe.Successful.Title" = "Subscription successful!";
|
||||
"Stars.Transfer.Subscribe.Successful.Text" = "%1$@ transferred to %2$@.";
|
||||
|
||||
"Gallery.Ad" = "Ad";
|
||||
|
@ -305,7 +305,7 @@ public enum ResolvedUrl {
|
||||
case startAttach(peerId: PeerId, payload: String?, choose: ResolvedBotChoosePeerTypes?)
|
||||
case invoice(slug: String, invoice: TelegramMediaInvoice?)
|
||||
case premiumOffer(reference: String?)
|
||||
case starsTopup(amount: Int64?)
|
||||
case starsTopup(amount: Int64, purpose: String?)
|
||||
case chatFolder(slug: String)
|
||||
case story(peerId: PeerId, id: Int32)
|
||||
case boost(peerId: PeerId?, status: ChannelBoostStatus?, myBoostStatus: MyBoostStatus?)
|
||||
@ -917,7 +917,7 @@ public protocol SharedAccountContext: AnyObject {
|
||||
func makeProxySettingsController(context: AccountContext) -> ViewController
|
||||
func makeLocalizationListController(context: AccountContext) -> ViewController
|
||||
func makeCreateGroupController(context: AccountContext, peerIds: [PeerId], initialTitle: String?, mode: CreateGroupMode, completion: ((PeerId, @escaping () -> Void) -> Void)?) -> ViewController
|
||||
func makeChatRecentActionsController(context: AccountContext, peer: Peer, adminPeerId: PeerId?) -> ViewController
|
||||
func makeChatRecentActionsController(context: AccountContext, peer: Peer, adminPeerId: PeerId?, starsState: StarsRevenueStats?) -> ViewController
|
||||
func makePrivacyAndSecurityController(context: AccountContext) -> ViewController
|
||||
func makeBioPrivacyController(context: AccountContext, settings: Promise<AccountPrivacySettings?>, present: @escaping (ViewController) -> Void)
|
||||
func makeBirthdayPrivacyController(context: AccountContext, settings: Promise<AccountPrivacySettings?>, openedFromBirthdayScreen: Bool, present: @escaping (ViewController) -> Void)
|
||||
|
@ -123,7 +123,8 @@ public enum BoostSubject: Equatable {
|
||||
}
|
||||
|
||||
public enum StarsPurchasePurpose: Equatable {
|
||||
case generic(requiredStars: Int64?)
|
||||
case generic
|
||||
case topUp(requiredStars: Int64, purpose: String?)
|
||||
case transfer(peerId: EnginePeer.Id, requiredStars: Int64)
|
||||
case subscription(peerId: EnginePeer.Id, requiredStars: Int64, renew: Bool)
|
||||
case gift(peerId: EnginePeer.Id)
|
||||
|
@ -256,7 +256,13 @@ public func chatMessageGalleryControllerData(context: AccountContext, chatLocati
|
||||
}
|
||||
}
|
||||
|
||||
if message.containsSecretMedia {
|
||||
if let adAttribute = message.adAttribute, adAttribute.hasContentMedia {
|
||||
let gallery = GalleryController(context: context, source: .standaloneMessage(message, mediaIndex), invertItemOrder: reverseMessageGalleryOrder, streamSingleVideo: stream, fromPlayingVideo: autoplayingVideo, landscape: landscape, timecode: nil, playbackRate: 1.0, synchronousLoad: synchronousLoad, replaceRootController: { [weak navigationController] controller, ready in
|
||||
navigationController?.replaceTopController(controller, animated: false, ready: ready)
|
||||
}, baseNavigationController: navigationController, actionInteraction: actionInteraction)
|
||||
gallery.temporaryDoNotWaitForReady = autoplayingVideo
|
||||
return .gallery(.single(gallery))
|
||||
} else if message.containsSecretMedia {
|
||||
let gallery = SecretMediaPreviewController(context: context, messageId: message.id)
|
||||
return .secretGallery(gallery)
|
||||
} else {
|
||||
|
@ -770,10 +770,18 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
||||
}
|
||||
}
|
||||
|
||||
func setup(origin: GalleryItemOriginData?, caption: NSAttributedString) {
|
||||
let titleText = origin?.title
|
||||
func setup(origin: GalleryItemOriginData?, caption: NSAttributedString, isAd: Bool = false) {
|
||||
var titleText = origin?.title
|
||||
let dateText = origin?.timestamp.flatMap { humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: $0).string }
|
||||
|
||||
let caption = caption.mutableCopy() as! NSMutableAttributedString
|
||||
if isAd {
|
||||
if let titleText, !titleText.isEmpty {
|
||||
caption.insert(NSAttributedString(string: titleText + "\n", font: Font.semibold(17.0), textColor: .white), at: 0)
|
||||
}
|
||||
titleText = nil
|
||||
}
|
||||
|
||||
if self.currentMessageText != caption || self.currentAuthorNameText != titleText || self.currentDateText != dateText {
|
||||
self.currentMessageText = caption
|
||||
self.currentAuthorNameText = titleText
|
||||
@ -820,9 +828,12 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
||||
if Namespaces.Message.allNonRegular.contains(message.id.namespace) || message.timestamp == 0 {
|
||||
displayInfo = false
|
||||
}
|
||||
if let _ = message.adAttribute {
|
||||
displayInfo = false
|
||||
}
|
||||
|
||||
var canDelete: Bool
|
||||
var canShare = !message.containsSecretMedia && !Namespaces.Message.allNonRegular.contains(message.id.namespace)
|
||||
var canShare = !message.containsSecretMedia && !Namespaces.Message.allNonRegular.contains(message.id.namespace) && message.adAttribute == nil
|
||||
|
||||
var canFullscreen = false
|
||||
|
||||
@ -922,13 +933,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
||||
}
|
||||
|
||||
var dateText = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: message.timestamp).string
|
||||
if !displayInfo {
|
||||
authorNameText = ""
|
||||
dateText = ""
|
||||
canEdit = false
|
||||
}
|
||||
|
||||
var messageText = NSAttributedString(string: "")
|
||||
|
||||
var messageText = NSMutableAttributedString(string: "")
|
||||
var hasCaption = false
|
||||
for media in message.media {
|
||||
if media is TelegramMediaPaidContent {
|
||||
@ -991,7 +997,14 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
||||
codeHighlightState.disposable.dispose()
|
||||
}
|
||||
|
||||
messageText = galleryCaptionStringWithAppliedEntities(context: self.context, text: text, entities: entities, message: message, cachedMessageSyntaxHighlight: cachedMessageSyntaxHighlight)
|
||||
messageText = galleryCaptionStringWithAppliedEntities(context: self.context, text: text, entities: entities, message: message, cachedMessageSyntaxHighlight: cachedMessageSyntaxHighlight).mutableCopy() as! NSMutableAttributedString
|
||||
messageText.insert(NSAttributedString(string: (authorNameText ?? "") + "\n", font: Font.semibold(17.0), textColor: .white), at: 0)
|
||||
}
|
||||
|
||||
if !displayInfo {
|
||||
authorNameText = ""
|
||||
dateText = ""
|
||||
canEdit = false
|
||||
}
|
||||
|
||||
if self.currentMessageText != messageText || canDelete != !self.deleteButton.isHidden || canFullscreen != !self.fullscreenButton.isHidden || canShare != !self.actionButton.isHidden || canEdit != !self.editButton.isHidden || self.currentAuthorNameText != authorNameText || self.currentDateText != dateText {
|
||||
|
@ -168,7 +168,9 @@ class ChatImageGalleryItem: GalleryItem {
|
||||
}
|
||||
}
|
||||
|
||||
if let location = self.location {
|
||||
if let _ = message.adAttribute {
|
||||
node._title.set(.single(self.presentationData.strings.Gallery_Ad))
|
||||
} else if let location = self.location {
|
||||
node._title.set(.single(self.presentationData.strings.Items_NOfM("\(location.index + 1)", "\(location.count)").string))
|
||||
}
|
||||
|
||||
|
@ -1528,15 +1528,17 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
|
||||
self.playbackRatePromise.set(self.playbackRate ?? 1.0)
|
||||
|
||||
var isAd = false
|
||||
if let contentInfo = item.contentInfo {
|
||||
switch contentInfo {
|
||||
case let .message(message, _):
|
||||
isAd = message.adAttribute != nil
|
||||
self.footerContentNode.setMessage(message, displayInfo: !item.displayInfoOnTop, peerIsCopyProtected: item.peerIsCopyProtected)
|
||||
case let .webPage(webPage, media, _):
|
||||
self.footerContentNode.setWebPage(webPage, media: media)
|
||||
}
|
||||
}
|
||||
self.footerContentNode.setup(origin: item.originData, caption: item.caption)
|
||||
self.footerContentNode.setup(origin: item.originData, caption: item.caption, isAd: isAd)
|
||||
}
|
||||
|
||||
override func controlsVisibilityUpdated(isVisible: Bool) {
|
||||
|
@ -857,18 +857,20 @@ public func inviteLinkEditController(context: AccountContext, updatedPresentatio
|
||||
|
||||
private struct StarsSubscriptionConfiguration {
|
||||
static var defaultValue: StarsSubscriptionConfiguration {
|
||||
return StarsSubscriptionConfiguration(maxFee: 2500)
|
||||
return StarsSubscriptionConfiguration(maxFee: 2500, usdSellRate: 2000)
|
||||
}
|
||||
|
||||
let maxFee: Int64?
|
||||
let usdSellRate: Int64?
|
||||
|
||||
fileprivate init(maxFee: Int64?) {
|
||||
fileprivate init(maxFee: Int64?, usdSellRate: Int64?) {
|
||||
self.maxFee = maxFee
|
||||
self.usdSellRate = usdSellRate
|
||||
}
|
||||
|
||||
public static func with(appConfiguration: AppConfiguration) -> StarsSubscriptionConfiguration {
|
||||
if let data = appConfiguration.data, let value = data["stars_subscription_amount_max"] as? Double {
|
||||
return StarsSubscriptionConfiguration(maxFee: Int64(value))
|
||||
if let data = appConfiguration.data, let value = data["stars_subscription_amount_max"] as? Double, let usdRate = data["stars_usd_sell_rate_x1000"] as? Double {
|
||||
return StarsSubscriptionConfiguration(maxFee: Int64(value), usdSellRate: Int64(usdRate))
|
||||
} else {
|
||||
return .defaultValue
|
||||
}
|
||||
|
@ -182,6 +182,7 @@ public class ItemListInviteLinkItemNode: ListViewItemNode, ItemListItemNode {
|
||||
private var absoluteLocation: (CGRect, CGSize)?
|
||||
|
||||
private var currentColor: ItemBackgroundColor?
|
||||
private var currentIsPaid: Bool?
|
||||
private var layoutParams: (ItemListInviteLinkItem, ListViewItemLayoutParams, ItemListNeighbors, Bool, Bool)?
|
||||
|
||||
public var tag: ItemListItemTag?
|
||||
@ -548,8 +549,12 @@ public class ItemListInviteLinkItemNode: ListViewItemNode, ItemListItemNode {
|
||||
strongSelf.bottomStripeNode.backgroundColor = itemSeparatorColor
|
||||
strongSelf.backgroundNode.backgroundColor = itemBackgroundColor
|
||||
strongSelf.highlightedBackgroundNode.backgroundColor = item.presentationData.theme.list.itemHighlightedBackgroundColor
|
||||
|
||||
if let _ = item.invite?.pricing {
|
||||
}
|
||||
|
||||
let isPaid = item.invite?.pricing != nil
|
||||
if updatedTheme != nil || strongSelf.currentIsPaid != isPaid {
|
||||
strongSelf.currentIsPaid = isPaid
|
||||
if isPaid {
|
||||
strongSelf.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Item List/SubscriptionLink"), color: item.presentationData.theme.list.itemCheckColors.foregroundColor)
|
||||
} else {
|
||||
strongSelf.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Item List/InviteLink"), color: item.presentationData.theme.list.itemCheckColors.foregroundColor)
|
||||
|
@ -1358,6 +1358,8 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
let _ = statusApply()
|
||||
if case let .account(context) = item.context {
|
||||
let _ = labelApply(TextNodeWithEntities.Arguments(context: context, cache: item.context.animationCache, renderer: item.context.animationRenderer, placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, attemptSynchronous: false))
|
||||
} else {
|
||||
let _ = labelApply(nil)
|
||||
}
|
||||
strongSelf.labelNode.textNode.isHidden = labelAttributedString == nil
|
||||
|
||||
|
@ -709,7 +709,7 @@ public func channelAdminsController(context: AccountContext, updatedPresentation
|
||||
}
|
||||
if case .legacyGroup = peer {
|
||||
} else {
|
||||
pushControllerImpl?(context.sharedContext.makeChatRecentActionsController(context: context, peer: peer._asPeer(), adminPeerId: nil))
|
||||
pushControllerImpl?(context.sharedContext.makeChatRecentActionsController(context: context, peer: peer._asPeer(), adminPeerId: nil, starsState: nil))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -890,7 +890,7 @@ public func groupStatsController(context: AccountContext, updatedPresentationDat
|
||||
let _ = (context.account.postbox.loadedPeerWithId(peerId)
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
let controller = context.sharedContext.makeChatRecentActionsController(context: context, peer: peer, adminPeerId: participantPeerId)
|
||||
let controller = context.sharedContext.makeChatRecentActionsController(context: context, peer: peer, adminPeerId: participantPeerId, starsState: nil)
|
||||
navigationController.pushViewController(controller)
|
||||
})
|
||||
}
|
||||
|
@ -881,7 +881,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-651419003] = { return Api.SendMessageAction.parse_speakingInGroupCallAction($0) }
|
||||
dict[-1239335713] = { return Api.ShippingOption.parse_shippingOption($0) }
|
||||
dict[-425595208] = { return Api.SmsJob.parse_smsJob($0) }
|
||||
dict[-1108478618] = { return Api.SponsoredMessage.parse_sponsoredMessage($0) }
|
||||
dict[1301522832] = { return Api.SponsoredMessage.parse_sponsoredMessage($0) }
|
||||
dict[1124938064] = { return Api.SponsoredMessageReportOption.parse_sponsoredMessageReportOption($0) }
|
||||
dict[1577421297] = { return Api.StarsGiftOption.parse_starsGiftOption($0) }
|
||||
dict[2033461574] = { return Api.StarsRevenueStatus.parse_starsRevenueStatus($0) }
|
||||
|
@ -441,14 +441,14 @@ public extension Api {
|
||||
}
|
||||
}
|
||||
public extension Api {
|
||||
enum SponsoredMessage: TypeConstructorDescription {
|
||||
case sponsoredMessage(flags: Int32, randomId: Buffer, url: String, title: String, message: String, entities: [Api.MessageEntity]?, photo: Api.Photo?, color: Api.PeerColor?, buttonText: String, sponsorInfo: String?, additionalInfo: String?)
|
||||
indirect enum SponsoredMessage: TypeConstructorDescription {
|
||||
case sponsoredMessage(flags: Int32, randomId: Buffer, url: String, title: String, message: String, entities: [Api.MessageEntity]?, photo: Api.Photo?, media: Api.MessageMedia?, color: Api.PeerColor?, buttonText: String, sponsorInfo: String?, additionalInfo: String?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .sponsoredMessage(let flags, let randomId, let url, let title, let message, let entities, let photo, let color, let buttonText, let sponsorInfo, let additionalInfo):
|
||||
case .sponsoredMessage(let flags, let randomId, let url, let title, let message, let entities, let photo, let media, let color, let buttonText, let sponsorInfo, let additionalInfo):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1108478618)
|
||||
buffer.appendInt32(1301522832)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeBytes(randomId, buffer: buffer, boxed: false)
|
||||
@ -461,6 +461,7 @@ public extension Api {
|
||||
item.serialize(buffer, true)
|
||||
}}
|
||||
if Int(flags) & Int(1 << 6) != 0 {photo!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 14) != 0 {media!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 13) != 0 {color!.serialize(buffer, true)}
|
||||
serializeString(buttonText, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 7) != 0 {serializeString(sponsorInfo!, buffer: buffer, boxed: false)}
|
||||
@ -471,8 +472,8 @@ public extension Api {
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .sponsoredMessage(let flags, let randomId, let url, let title, let message, let entities, let photo, let color, let buttonText, let sponsorInfo, let additionalInfo):
|
||||
return ("sponsoredMessage", [("flags", flags as Any), ("randomId", randomId as Any), ("url", url as Any), ("title", title as Any), ("message", message as Any), ("entities", entities as Any), ("photo", photo as Any), ("color", color as Any), ("buttonText", buttonText as Any), ("sponsorInfo", sponsorInfo as Any), ("additionalInfo", additionalInfo as Any)])
|
||||
case .sponsoredMessage(let flags, let randomId, let url, let title, let message, let entities, let photo, let media, let color, let buttonText, let sponsorInfo, let additionalInfo):
|
||||
return ("sponsoredMessage", [("flags", flags as Any), ("randomId", randomId as Any), ("url", url as Any), ("title", title as Any), ("message", message as Any), ("entities", entities as Any), ("photo", photo as Any), ("media", media as Any), ("color", color as Any), ("buttonText", buttonText as Any), ("sponsorInfo", sponsorInfo as Any), ("additionalInfo", additionalInfo as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -495,16 +496,20 @@ public extension Api {
|
||||
if Int(_1!) & Int(1 << 6) != 0 {if let signature = reader.readInt32() {
|
||||
_7 = Api.parse(reader, signature: signature) as? Api.Photo
|
||||
} }
|
||||
var _8: Api.PeerColor?
|
||||
if Int(_1!) & Int(1 << 13) != 0 {if let signature = reader.readInt32() {
|
||||
_8 = Api.parse(reader, signature: signature) as? Api.PeerColor
|
||||
var _8: Api.MessageMedia?
|
||||
if Int(_1!) & Int(1 << 14) != 0 {if let signature = reader.readInt32() {
|
||||
_8 = Api.parse(reader, signature: signature) as? Api.MessageMedia
|
||||
} }
|
||||
var _9: Api.PeerColor?
|
||||
if Int(_1!) & Int(1 << 13) != 0 {if let signature = reader.readInt32() {
|
||||
_9 = Api.parse(reader, signature: signature) as? Api.PeerColor
|
||||
} }
|
||||
var _9: String?
|
||||
_9 = parseString(reader)
|
||||
var _10: String?
|
||||
if Int(_1!) & Int(1 << 7) != 0 {_10 = parseString(reader) }
|
||||
_10 = parseString(reader)
|
||||
var _11: String?
|
||||
if Int(_1!) & Int(1 << 8) != 0 {_11 = parseString(reader) }
|
||||
if Int(_1!) & Int(1 << 7) != 0 {_11 = parseString(reader) }
|
||||
var _12: String?
|
||||
if Int(_1!) & Int(1 << 8) != 0 {_12 = parseString(reader) }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
@ -512,12 +517,13 @@ public extension Api {
|
||||
let _c5 = _5 != nil
|
||||
let _c6 = (Int(_1!) & Int(1 << 1) == 0) || _6 != nil
|
||||
let _c7 = (Int(_1!) & Int(1 << 6) == 0) || _7 != nil
|
||||
let _c8 = (Int(_1!) & Int(1 << 13) == 0) || _8 != nil
|
||||
let _c9 = _9 != nil
|
||||
let _c10 = (Int(_1!) & Int(1 << 7) == 0) || _10 != nil
|
||||
let _c11 = (Int(_1!) & Int(1 << 8) == 0) || _11 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 {
|
||||
return Api.SponsoredMessage.sponsoredMessage(flags: _1!, randomId: _2!, url: _3!, title: _4!, message: _5!, entities: _6, photo: _7, color: _8, buttonText: _9!, sponsorInfo: _10, additionalInfo: _11)
|
||||
let _c8 = (Int(_1!) & Int(1 << 14) == 0) || _8 != nil
|
||||
let _c9 = (Int(_1!) & Int(1 << 13) == 0) || _9 != nil
|
||||
let _c10 = _10 != nil
|
||||
let _c11 = (Int(_1!) & Int(1 << 7) == 0) || _11 != nil
|
||||
let _c12 = (Int(_1!) & Int(1 << 8) == 0) || _12 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 {
|
||||
return Api.SponsoredMessage.sponsoredMessage(flags: _1!, randomId: _2!, url: _3!, title: _4!, message: _5!, entities: _6, photo: _7, media: _8, color: _9, buttonText: _10!, sponsorInfo: _11, additionalInfo: _12)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
@ -14,8 +14,9 @@ public final class AdMessageAttribute: MessageAttribute {
|
||||
public let sponsorInfo: String?
|
||||
public let additionalInfo: String?
|
||||
public let canReport: Bool
|
||||
public let hasContentMedia: Bool
|
||||
|
||||
public init(opaqueId: Data, messageType: MessageType, url: String, buttonText: String, sponsorInfo: String?, additionalInfo: String?, canReport: Bool) {
|
||||
public init(opaqueId: Data, messageType: MessageType, url: String, buttonText: String, sponsorInfo: String?, additionalInfo: String?, canReport: Bool, hasContentMedia: Bool) {
|
||||
self.opaqueId = opaqueId
|
||||
self.messageType = messageType
|
||||
self.url = url
|
||||
@ -23,6 +24,7 @@ public final class AdMessageAttribute: MessageAttribute {
|
||||
self.sponsorInfo = sponsorInfo
|
||||
self.additionalInfo = additionalInfo
|
||||
self.canReport = canReport
|
||||
self.hasContentMedia = hasContentMedia
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
|
@ -12,6 +12,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
case text
|
||||
case textEntities
|
||||
case media
|
||||
case contentMedia
|
||||
case color
|
||||
case backgroundEmojiId
|
||||
case url
|
||||
@ -32,6 +33,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
public let text: String
|
||||
public let textEntities: [MessageTextEntity]
|
||||
public let media: [Media]
|
||||
public let contentMedia: [Media]
|
||||
public let color: PeerNameColor?
|
||||
public let backgroundEmojiId: Int64?
|
||||
public let url: String
|
||||
@ -47,6 +49,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
text: String,
|
||||
textEntities: [MessageTextEntity],
|
||||
media: [Media],
|
||||
contentMedia: [Media],
|
||||
color: PeerNameColor?,
|
||||
backgroundEmojiId: Int64?,
|
||||
url: String,
|
||||
@ -61,6 +64,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
self.text = text
|
||||
self.textEntities = textEntities
|
||||
self.media = media
|
||||
self.contentMedia = contentMedia
|
||||
self.color = color
|
||||
self.backgroundEmojiId = backgroundEmojiId
|
||||
self.url = url
|
||||
@ -89,6 +93,12 @@ private class AdMessagesHistoryContextImpl {
|
||||
self.media = mediaData.compactMap { data -> Media? in
|
||||
return PostboxDecoder(buffer: MemoryBuffer(data: data)).decodeRootObject() as? Media
|
||||
}
|
||||
|
||||
let contentMediaData = try container.decode([Data].self, forKey: .contentMedia)
|
||||
self.contentMedia = contentMediaData.compactMap { data -> Media? in
|
||||
return PostboxDecoder(buffer: MemoryBuffer(data: data)).decodeRootObject() as? Media
|
||||
}
|
||||
|
||||
self.color = try container.decodeIfPresent(Int32.self, forKey: .color).flatMap { PeerNameColor(rawValue: $0) }
|
||||
self.backgroundEmojiId = try container.decodeIfPresent(Int64.self, forKey: .backgroundEmojiId)
|
||||
|
||||
@ -116,6 +126,13 @@ private class AdMessagesHistoryContextImpl {
|
||||
return encoder.makeData()
|
||||
}
|
||||
try container.encode(mediaData, forKey: .media)
|
||||
|
||||
let contentMediaData = self.contentMedia.map { media -> Data in
|
||||
let encoder = PostboxEncoder()
|
||||
encoder.encodeRootObject(media)
|
||||
return encoder.makeData()
|
||||
}
|
||||
try container.encode(contentMediaData, forKey: .contentMedia)
|
||||
|
||||
try container.encodeIfPresent(self.color?.rawValue, forKey: .color)
|
||||
try container.encodeIfPresent(self.backgroundEmojiId, forKey: .backgroundEmojiId)
|
||||
@ -153,6 +170,14 @@ private class AdMessagesHistoryContextImpl {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if lhs.contentMedia.count != rhs.contentMedia.count {
|
||||
return false
|
||||
}
|
||||
for i in 0 ..< lhs.contentMedia.count {
|
||||
if !lhs.contentMedia[i].isEqual(to: rhs.contentMedia[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if lhs.url != rhs.url {
|
||||
return false
|
||||
}
|
||||
@ -181,7 +206,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
case .recommended:
|
||||
mappedMessageType = .recommended
|
||||
}
|
||||
attributes.append(AdMessageAttribute(opaqueId: self.opaqueId, messageType: mappedMessageType, url: self.url, buttonText: self.buttonText, sponsorInfo: self.sponsorInfo, additionalInfo: self.additionalInfo, canReport: self.canReport))
|
||||
attributes.append(AdMessageAttribute(opaqueId: self.opaqueId, messageType: mappedMessageType, url: self.url, buttonText: self.buttonText, sponsorInfo: self.sponsorInfo, additionalInfo: self.additionalInfo, canReport: self.canReport, hasContentMedia: !self.contentMedia.isEmpty))
|
||||
if !self.textEntities.isEmpty {
|
||||
let attribute = TextEntitiesMessageAttribute(entities: self.textEntities)
|
||||
attributes.append(attribute)
|
||||
@ -241,7 +266,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
author: author,
|
||||
text: self.text,
|
||||
attributes: attributes,
|
||||
media: self.media,
|
||||
media: !self.contentMedia.isEmpty ? self.contentMedia : self.media,
|
||||
peers: messagePeers,
|
||||
associatedMessages: SimpleDictionary<MessageId, Message>(),
|
||||
associatedMessageIds: [],
|
||||
@ -422,7 +447,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
|
||||
for message in messages {
|
||||
switch message {
|
||||
case let .sponsoredMessage(flags, randomId, url, title, message, entities, photo, color, buttonText, sponsorInfo, additionalInfo):
|
||||
case let .sponsoredMessage(flags, randomId, url, title, message, entities, photo, media, color, buttonText, sponsorInfo, additionalInfo):
|
||||
var parsedEntities: [MessageTextEntity] = []
|
||||
if let entities = entities {
|
||||
parsedEntities = messageTextEntitiesFromApiEntities(entities)
|
||||
@ -442,6 +467,8 @@ private class AdMessagesHistoryContextImpl {
|
||||
}
|
||||
|
||||
let photo = photo.flatMap { telegramMediaImageFromApiPhoto($0) }
|
||||
let (contentMedia, _, _, _, _) = textMediaAndExpirationTimerFromApiMedia(media, peerId)
|
||||
|
||||
parsedMessages.append(CachedMessage(
|
||||
opaqueId: randomId.makeData(),
|
||||
messageType: isRecommended ? .recommended : .sponsored,
|
||||
@ -449,6 +476,7 @@ private class AdMessagesHistoryContextImpl {
|
||||
text: message,
|
||||
textEntities: parsedEntities,
|
||||
media: photo.flatMap { [$0] } ?? [],
|
||||
contentMedia: contentMedia.flatMap { [$0] } ?? [],
|
||||
color: nameColorIndex.flatMap { PeerNameColor(rawValue: $0) },
|
||||
backgroundEmojiId: backgroundEmojiId,
|
||||
url: url,
|
||||
|
@ -686,7 +686,7 @@ public final class StarsContext {
|
||||
return peerId!
|
||||
}
|
||||
|
||||
var currentState: StarsContext.State? {
|
||||
public var currentState: StarsContext.State? {
|
||||
var state: StarsContext.State?
|
||||
self.impl.syncWith { impl in
|
||||
state = impl._state
|
||||
|
@ -637,6 +637,14 @@ public struct PeerInvitationImportersState: Equatable {
|
||||
public var about: String?
|
||||
public var approvedBy: PeerId?
|
||||
public var joinedViaFolderLink: Bool
|
||||
|
||||
public init(peer: RenderedPeer, date: Int32, about: String? = nil, approvedBy: PeerId? = nil, joinedViaFolderLink: Bool) {
|
||||
self.peer = peer
|
||||
self.date = date
|
||||
self.about = about
|
||||
self.approvedBy = approvedBy
|
||||
self.joinedViaFolderLink = joinedViaFolderLink
|
||||
}
|
||||
}
|
||||
public var importers: [Importer]
|
||||
public var isLoadingMore: Bool
|
||||
|
@ -318,6 +318,12 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
|
||||
flags.remove(.preferMediaInline)
|
||||
mediaAndFlags = (mediaAndFlagsValue.0, flags)
|
||||
}
|
||||
if let adAttribute = message.adAttribute, adAttribute.hasContentMedia {
|
||||
var flags = mediaAndFlagsValue.1
|
||||
flags.remove(.preferMediaInline)
|
||||
flags.insert(.preferMediaBeforeText)
|
||||
mediaAndFlags = (mediaAndFlagsValue.0, flags)
|
||||
}
|
||||
}
|
||||
|
||||
var contentMediaAspectFilled = false
|
||||
|
@ -82,7 +82,7 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
|
||||
}
|
||||
}
|
||||
}
|
||||
let openChatMessageMode: ChatControllerInteractionOpenMessageMode
|
||||
var openChatMessageMode: ChatControllerInteractionOpenMessageMode
|
||||
switch mode {
|
||||
case .default:
|
||||
openChatMessageMode = .default
|
||||
@ -91,6 +91,9 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
|
||||
case .automaticPlayback:
|
||||
openChatMessageMode = .automaticPlayback
|
||||
}
|
||||
if let adAttribute = item.message.adAttribute, adAttribute.hasContentMedia {
|
||||
openChatMessageMode = .automaticPlayback
|
||||
}
|
||||
if !item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: openChatMessageMode)) {
|
||||
if let webPage = strongSelf.webPage, case let .Loaded(content) = webPage.content {
|
||||
var isConcealed = true
|
||||
|
@ -22,6 +22,8 @@ public final class ChatRecentActionsController: TelegramBaseController {
|
||||
private let context: AccountContext
|
||||
private let peer: Peer
|
||||
private let initialAdminPeerId: PeerId?
|
||||
let starsState: StarsRevenueStats?
|
||||
|
||||
private var presentationData: PresentationData
|
||||
private var presentationDataPromise = Promise<PresentationData>()
|
||||
override public var updatedPresentationData: (PresentationData, Signal<PresentationData, NoError>) {
|
||||
@ -37,10 +39,11 @@ public final class ChatRecentActionsController: TelegramBaseController {
|
||||
|
||||
private var adminsDisposable: Disposable?
|
||||
|
||||
public init(context: AccountContext, peer: Peer, adminPeerId: PeerId?) {
|
||||
public init(context: AccountContext, peer: Peer, adminPeerId: PeerId?, starsState: StarsRevenueStats?) {
|
||||
self.context = context
|
||||
self.peer = peer
|
||||
self.initialAdminPeerId = adminPeerId
|
||||
self.starsState = starsState
|
||||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
|
@ -210,10 +210,16 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
])])
|
||||
strongSelf.presentController(actionSheet, .window(.root), nil)
|
||||
} else {
|
||||
let controller = inviteLinkEditController(context: strongSelf.context, updatedPresentationData: strongSelf.controller?.updatedPresentationData, peerId: peer.id, invite: invite, completion: { [weak self] _ in
|
||||
self?.eventLogContext.reload()
|
||||
})
|
||||
controller.navigationPresentation = .modal
|
||||
let controller = InviteLinkViewController(
|
||||
context: strongSelf.context,
|
||||
updatedPresentationData: strongSelf.controller?.updatedPresentationData,
|
||||
peerId: peer.id,
|
||||
invite: invite,
|
||||
invitationsContext: nil,
|
||||
revokedInvitationsContext: nil,
|
||||
importersContext: nil,
|
||||
starsState: strongSelf.controller?.starsState
|
||||
)
|
||||
strongSelf.pushController(controller)
|
||||
}
|
||||
return true
|
||||
|
@ -8584,7 +8584,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
guard let peer = self.data?.peer else {
|
||||
return
|
||||
}
|
||||
let controller = self.context.sharedContext.makeChatRecentActionsController(context: self.context, peer: peer, adminPeerId: nil)
|
||||
let controller = self.context.sharedContext.makeChatRecentActionsController(context: self.context, peer: peer, adminPeerId: nil, starsState: self.data?.starsRevenueStatsState)
|
||||
self.controller?.push(controller)
|
||||
}
|
||||
|
||||
|
@ -208,9 +208,24 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
|
||||
|
||||
let textString: String
|
||||
switch context.component.purpose {
|
||||
case let .generic(requiredStars):
|
||||
let _ = requiredStars
|
||||
case .generic:
|
||||
textString = strings.Stars_Purchase_GetStarsInfo
|
||||
case let .topUp(_, purpose):
|
||||
var text = strings.Stars_Purchase_GenericPurchasePurpose
|
||||
if let purpose, !purpose.isEmpty {
|
||||
switch purpose {
|
||||
case "subs":
|
||||
text = strings.Stars_Purchase_PurchasePurpose_subs
|
||||
default:
|
||||
let key = "Stars.Purchase.PurchasePurpose.\(purpose)"
|
||||
if let string = strings.primaryComponent.dict[key] {
|
||||
text = string
|
||||
} else if let string = strings.secondaryComponent?.dict[key] {
|
||||
text = string
|
||||
}
|
||||
}
|
||||
}
|
||||
textString = text
|
||||
case .gift:
|
||||
textString = strings.Stars_Purchase_GiftInfo(component.peers.first?.value.compactDisplayTitle ?? "").string
|
||||
case .transfer:
|
||||
@ -816,12 +831,10 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
|
||||
|
||||
let titleText: String
|
||||
switch context.component.purpose {
|
||||
case let .generic(requiredStars):
|
||||
if let requiredStars {
|
||||
titleText = strings.Stars_Purchase_StarsNeeded(Int32(requiredStars))
|
||||
} else {
|
||||
titleText = strings.Stars_Purchase_GetStars
|
||||
}
|
||||
case .generic:
|
||||
titleText = strings.Stars_Purchase_GetStars
|
||||
case let .topUp(requiredStars, _):
|
||||
titleText = strings.Stars_Purchase_StarsNeeded(Int32(requiredStars))
|
||||
case .gift:
|
||||
titleText = strings.Stars_Purchase_GiftStars
|
||||
case let .transfer(_, requiredStars), let .subscription(_, requiredStars, _), let .unlockMedia(requiredStars):
|
||||
@ -1226,7 +1239,7 @@ private extension StarsPurchasePurpose {
|
||||
|
||||
var requiredStars: Int64? {
|
||||
switch self {
|
||||
case let .generic(requiredStars):
|
||||
case let .topUp(requiredStars, _):
|
||||
return requiredStars
|
||||
case let .transfer(_, requiredStars):
|
||||
return requiredStars
|
||||
|
@ -36,7 +36,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
let openMedia: ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void
|
||||
let openAppExamples: () -> Void
|
||||
let copyTransactionId: (String) -> Void
|
||||
let updateSubscription: (StarsTransactionScreen.SubscriptionAction) -> Void
|
||||
let updateSubscription: () -> Void
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
@ -47,7 +47,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
openMedia: @escaping ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void,
|
||||
openAppExamples: @escaping () -> Void,
|
||||
copyTransactionId: @escaping (String) -> Void,
|
||||
updateSubscription: @escaping (StarsTransactionScreen.SubscriptionAction) -> Void
|
||||
updateSubscription: @escaping () -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.subject = subject
|
||||
@ -199,6 +199,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
var countOnTop = false
|
||||
var transactionId: String?
|
||||
let date: Int32
|
||||
var additionalDate: Int32?
|
||||
var via: String?
|
||||
var messageId: EngineMessage.Id?
|
||||
var toPeer: EnginePeer?
|
||||
@ -230,14 +231,41 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
descriptionText = ""
|
||||
count = subscription.pricing.amount
|
||||
date = subscription.untilDate
|
||||
if let creationDate = (subscription.peer._asPeer() as? TelegramChannel)?.creationDate, creationDate > 0 {
|
||||
additionalDate = creationDate
|
||||
} else {
|
||||
additionalDate = nil
|
||||
}
|
||||
toPeer = subscription.peer
|
||||
transactionPeer = .peer(subscription.peer)
|
||||
isSubscription = true
|
||||
|
||||
if subscription.flags.contains(.isCancelled) {
|
||||
statusText = strings.Stars_Transaction_Subscription_Cancelled
|
||||
statusIsDestructive = true
|
||||
buttonText = strings.Stars_Transaction_Subscription_Renew
|
||||
var hasLeft = false
|
||||
if let toPeer, case let .channel(channel) = toPeer, channel.participationStatus == .left {
|
||||
hasLeft = true
|
||||
}
|
||||
|
||||
if hasLeft {
|
||||
if subscription.flags.contains(.isCancelled) {
|
||||
statusText = strings.Stars_Transaction_Subscription_Cancelled
|
||||
statusIsDestructive = true
|
||||
if date > Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) {
|
||||
buttonText = strings.Stars_Transaction_Subscription_Renew
|
||||
} else {
|
||||
if let _ = subscription.inviteHash {
|
||||
buttonText = strings.Stars_Transaction_Subscription_JoinAgainChannel
|
||||
} else {
|
||||
buttonText = strings.Common_OK
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if date < Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) {
|
||||
buttonText = strings.Stars_Transaction_Subscription_Renew
|
||||
} else {
|
||||
statusText = strings.Stars_Transaction_Subscription_LeftChannel(stringForMediumDate(timestamp: subscription.untilDate, strings: strings, dateTimeFormat: dateTimeFormat, withTime: false)).string
|
||||
buttonText = strings.Stars_Transaction_Subscription_JoinChannel
|
||||
}
|
||||
}
|
||||
isCancelled = true
|
||||
} else {
|
||||
statusText = strings.Stars_Transaction_Subscription_Active(stringForMediumDate(timestamp: subscription.untilDate, strings: strings, dateTimeFormat: dateTimeFormat, withTime: false)).string
|
||||
@ -628,16 +656,26 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
))
|
||||
}
|
||||
|
||||
if isSubscription, let additionalDate {
|
||||
tableItems.append(.init(
|
||||
id: "additionalDate",
|
||||
title: strings.Stars_Transaction_Subscription_Status_Subscribed,
|
||||
component: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(NSAttributedString(string: stringForMediumDate(timestamp: additionalDate, strings: strings, dateTimeFormat: dateTimeFormat), font: tableFont, textColor: tableTextColor)))
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
let dateTitle: String
|
||||
if isSubscription {
|
||||
if isCancelled {
|
||||
if date > Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) {
|
||||
if date > Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) {
|
||||
if isCancelled {
|
||||
dateTitle = strings.Stars_Transaction_Subscription_Status_Expires
|
||||
} else {
|
||||
dateTitle = strings.Stars_Transaction_Subscription_Status_Expired
|
||||
dateTitle = strings.Stars_Transaction_Subscription_Status_Renews
|
||||
}
|
||||
} else {
|
||||
dateTitle = strings.Stars_Transaction_Subscription_Status_Renews
|
||||
dateTitle = strings.Stars_Transaction_Subscription_Status_Expired
|
||||
}
|
||||
} else if isSubscriber {
|
||||
dateTitle = strings.Stars_Transaction_Subscription_Status_Subscribed
|
||||
@ -652,6 +690,16 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
)
|
||||
))
|
||||
|
||||
if isSubscriber, let additionalDate {
|
||||
tableItems.append(.init(
|
||||
id: "additionalDate",
|
||||
title: strings.Stars_Transaction_Subscription_Status_Renews,
|
||||
component: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(NSAttributedString(string: stringForMediumDate(timestamp: additionalDate, strings: strings, dateTimeFormat: dateTimeFormat), font: tableFont, textColor: tableTextColor)))
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
let table = table.update(
|
||||
component: TableComponent(
|
||||
theme: environment.theme,
|
||||
@ -857,13 +905,8 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
||||
isLoading: state.inProgress,
|
||||
action: {
|
||||
component.cancel(true)
|
||||
|
||||
if isSubscription {
|
||||
if buttonIsDestructive {
|
||||
component.updateSubscription(.cancel)
|
||||
} else {
|
||||
component.updateSubscription(.renew)
|
||||
}
|
||||
component.updateSubscription()
|
||||
}
|
||||
}
|
||||
),
|
||||
@ -899,7 +942,7 @@ private final class StarsTransactionSheetComponent: CombinedComponent {
|
||||
let openMedia: ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void
|
||||
let openAppExamples: () -> Void
|
||||
let copyTransactionId: (String) -> Void
|
||||
let updateSubscription: (StarsTransactionScreen.SubscriptionAction) -> Void
|
||||
let updateSubscription: () -> Void
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
@ -909,7 +952,7 @@ private final class StarsTransactionSheetComponent: CombinedComponent {
|
||||
openMedia: @escaping ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void,
|
||||
openAppExamples: @escaping () -> Void,
|
||||
copyTransactionId: @escaping (String) -> Void,
|
||||
updateSubscription: @escaping (StarsTransactionScreen.SubscriptionAction) -> Void
|
||||
updateSubscription: @escaping () -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.subject = subject
|
||||
@ -1061,7 +1104,7 @@ public class StarsTransactionScreen: ViewControllerComponentContainer {
|
||||
var openMediaImpl: (([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void)?
|
||||
var openAppExamplesImpl: (() -> Void)?
|
||||
var copyTransactionIdImpl: ((String) -> Void)?
|
||||
var updateSubscriptionImpl: ((StarsTransactionScreen.SubscriptionAction) -> Void)?
|
||||
var updateSubscriptionImpl: (() -> Void)?
|
||||
|
||||
super.init(
|
||||
context: context,
|
||||
@ -1083,8 +1126,8 @@ public class StarsTransactionScreen: ViewControllerComponentContainer {
|
||||
copyTransactionId: { transactionId in
|
||||
copyTransactionIdImpl?(transactionId)
|
||||
},
|
||||
updateSubscription: { action in
|
||||
updateSubscriptionImpl?(action)
|
||||
updateSubscription: {
|
||||
updateSubscriptionImpl?()
|
||||
}
|
||||
),
|
||||
navigationBarAppearance: .none,
|
||||
@ -1197,27 +1240,37 @@ public class StarsTransactionScreen: ViewControllerComponentContainer {
|
||||
HapticFeedback().tap()
|
||||
}
|
||||
|
||||
updateSubscriptionImpl = { [weak self] action in
|
||||
updateSubscriptionImpl = { [weak self] in
|
||||
guard let self, case let .subscription(subscription) = subject, let navigationController = self.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
updateSubscription(action == .cancel)
|
||||
|
||||
let title: String
|
||||
let text: String
|
||||
switch action {
|
||||
case .cancel:
|
||||
title = presentationData.strings.Stars_Transaction_Subscription_Cancelled_Title
|
||||
text = presentationData.strings.Stars_Transaction_Subscription_Cancelled_Text(subscription.peer.compactDisplayTitle, stringForMediumDate(timestamp: subscription.untilDate, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat)).string
|
||||
case .renew:
|
||||
title = presentationData.strings.Stars_Transaction_Subscription_Renewed_Title
|
||||
text = presentationData.strings.Stars_Transaction_Subscription_Renewed_Text(subscription.peer.compactDisplayTitle).string
|
||||
var titleAndText: (String, String)?
|
||||
if subscription.flags.contains(.isCancelled) {
|
||||
updateSubscription(false)
|
||||
if subscription.untilDate > Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) {
|
||||
titleAndText = (
|
||||
presentationData.strings.Stars_Transaction_Subscription_Renewed_Title,
|
||||
presentationData.strings.Stars_Transaction_Subscription_Renewed_Text(subscription.peer.compactDisplayTitle).string
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if subscription.untilDate < Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) {
|
||||
updateSubscription(false)
|
||||
} else {
|
||||
updateSubscription(true)
|
||||
titleAndText = (
|
||||
presentationData.strings.Stars_Transaction_Subscription_Cancelled_Title,
|
||||
presentationData.strings.Stars_Transaction_Subscription_Cancelled_Text(subscription.peer.compactDisplayTitle, stringForMediumDate(timestamp: subscription.untilDate, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat)).string
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let controller = UndoOverlayController(presentationData: presentationData, content: .invitedToVoiceChat(context: context, peer: subscription.peer, title: title, text: text, action: nil, duration: 3.0), elevatedLayout: false, position: .bottom, action: { _ in return true })
|
||||
Queue.mainQueue().after(0.6) {
|
||||
navigationController.presentOverlay(controller: controller)
|
||||
|
||||
if let (title, text) = titleAndText {
|
||||
let controller = UndoOverlayController(presentationData: presentationData, content: .invitedToVoiceChat(context: context, peer: subscription.peer, title: title, text: text, action: nil, duration: 3.0), elevatedLayout: false, position: .bottom, action: { _ in return true })
|
||||
Queue.mainQueue().after(0.6) {
|
||||
navigationController.presentOverlay(controller: controller)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -972,7 +972,7 @@ public final class StarsTransactionsScreen: ViewControllerComponentContainer {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let controller = context.sharedContext.makeStarsPurchaseScreen(context: context, starsContext: starsContext, options: options, purpose: .generic(requiredStars: nil), completion: { [weak self] stars in
|
||||
let controller = context.sharedContext.makeStarsPurchaseScreen(context: context, starsContext: starsContext, options: options, purpose: .generic, completion: { [weak self] stars in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
@ -348,8 +348,7 @@ private final class SheetContent: CombinedComponent {
|
||||
|
||||
let titleString: String
|
||||
if isSubscription {
|
||||
//TODO:localize
|
||||
titleString = "Subscribe to the Channel"
|
||||
titleString = strings.Stars_Transfer_Subscribe_Channel_Title
|
||||
} else {
|
||||
titleString = strings.Stars_Transfer_Title
|
||||
}
|
||||
@ -376,7 +375,7 @@ private final class SheetContent: CombinedComponent {
|
||||
let amount = component.invoice.totalAmount
|
||||
let infoText: String
|
||||
if case .starsChatSubscription = context.component.source {
|
||||
infoText = "Do you want to subscribe to **\(state.botPeer?.compactDisplayTitle ?? "")** for **\(strings.Stars_Transfer_Info_Stars(Int32(amount)))** per month?"
|
||||
infoText = strings.Stars_Transfer_SubscribeInfo(state.botPeer?.compactDisplayTitle ?? "", strings.Stars_Transfer_Info_Stars(Int32(amount))).string
|
||||
} else if !component.extendedMedia.isEmpty {
|
||||
var description: String = ""
|
||||
var photoCount: Int32 = 0
|
||||
@ -403,11 +402,20 @@ private final class SheetContent: CombinedComponent {
|
||||
description += "**\(strings.Stars_Transfer_SingleVideo)**"
|
||||
}
|
||||
}
|
||||
infoText = strings.Stars_Transfer_UnlockInfo(
|
||||
description,
|
||||
state.chatPeer?.compactDisplayTitle ?? "",
|
||||
strings.Stars_Transfer_Info_Stars(Int32(amount))
|
||||
).string
|
||||
|
||||
if let botPeerName = state.botPeer?.compactDisplayTitle {
|
||||
infoText = strings.Stars_Transfer_UnlockBotInfo(
|
||||
description,
|
||||
botPeerName,
|
||||
strings.Stars_Transfer_Info_Stars(Int32(amount))
|
||||
).string
|
||||
} else {
|
||||
infoText = strings.Stars_Transfer_UnlockInfo(
|
||||
description,
|
||||
state.chatPeer?.compactDisplayTitle ?? "",
|
||||
strings.Stars_Transfer_Info_Stars(Int32(amount))
|
||||
).string
|
||||
}
|
||||
} else {
|
||||
infoText = strings.Stars_Transfer_Info(
|
||||
component.invoice.title,
|
||||
@ -483,7 +491,7 @@ private final class SheetContent: CombinedComponent {
|
||||
let amountString = presentationStringsFormattedNumber(Int32(amount), presentationData.dateTimeFormat.groupingSeparator)
|
||||
let buttonAttributedString: NSMutableAttributedString
|
||||
if case .starsChatSubscription = component.source {
|
||||
buttonAttributedString = NSMutableAttributedString(string: "Subscribe", font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
|
||||
buttonAttributedString = NSMutableAttributedString(string: strings.Stars_Transfer_Subscribe, font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
|
||||
} else {
|
||||
buttonAttributedString = NSMutableAttributedString(string: "\(strings.Stars_Transfer_Pay) # \(amountString)", font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
|
||||
}
|
||||
@ -524,7 +532,7 @@ private final class SheetContent: CombinedComponent {
|
||||
} else if let peerId = state?.botPeer?.id {
|
||||
purpose = .transfer(peerId: peerId, requiredStars: invoice.totalAmount)
|
||||
} else {
|
||||
purpose = .generic(requiredStars: nil)
|
||||
purpose = .generic
|
||||
}
|
||||
let purchaseController = accountContext.sharedContext.makeStarsPurchaseScreen(
|
||||
context: accountContext,
|
||||
@ -549,9 +557,8 @@ private final class SheetContent: CombinedComponent {
|
||||
var title = presentationData.strings.Stars_Transfer_PurchasedTitle
|
||||
let text: String
|
||||
if isSubscription {
|
||||
//TODO:localize
|
||||
title = "Subscription successful!"
|
||||
text = "\(presentationData.strings.Stars_Transfer_Purchased_Stars(Int32(invoice.totalAmount))) transferred to \(botTitle)."
|
||||
title = presentationData.strings.Stars_Transfer_Subscribe_Successful_Title
|
||||
text = presentationData.strings.Stars_Transfer_Subscribe_Successful_Text(presentationData.strings.Stars_Transfer_Purchased_Stars(Int32(invoice.totalAmount)), botTitle).string
|
||||
} else if let _ = component.invoice.extendedMedia {
|
||||
text = presentationData.strings.Stars_Transfer_UnlockedText( presentationData.strings.Stars_Transfer_Purchased_Stars(Int32(invoice.totalAmount))).string
|
||||
} else {
|
||||
|
@ -706,12 +706,38 @@ func openResolvedUrlImpl(
|
||||
if let navigationController = navigationController {
|
||||
navigationController.pushViewController(controller, animated: true)
|
||||
}
|
||||
case let .starsTopup(amount):
|
||||
case let .starsTopup(amount, purpose):
|
||||
dismissInput()
|
||||
if let starsContext = context.starsContext {
|
||||
let controller = context.sharedContext.makeStarsPurchaseScreen(context: context, starsContext: starsContext, options: [], purpose: .generic(requiredStars: amount), completion: { _ in })
|
||||
if let navigationController = navigationController {
|
||||
navigationController.pushViewController(controller, animated: true)
|
||||
let proceed = {
|
||||
let controller = context.sharedContext.makeStarsPurchaseScreen(context: context, starsContext: starsContext, options: [], purpose: .topUp(requiredStars: amount, purpose: purpose), completion: { _ in })
|
||||
if let navigationController = navigationController {
|
||||
navigationController.pushViewController(controller, animated: true)
|
||||
}
|
||||
}
|
||||
if let currentState = starsContext.currentState, currentState.balance >= amount {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = UndoOverlayController(
|
||||
presentationData: presentationData,
|
||||
content: .universal(
|
||||
animation: "StarsBuy",
|
||||
scale: 0.066,
|
||||
colors: [:],
|
||||
title: nil,
|
||||
text: "You have enough stars at the moment.",
|
||||
customUndoText: "Buy Anyway",
|
||||
timeout: nil
|
||||
),
|
||||
elevatedLayout: true,
|
||||
action: { action in
|
||||
if case .undo = action {
|
||||
proceed()
|
||||
}
|
||||
return true
|
||||
})
|
||||
present(controller, nil)
|
||||
} else {
|
||||
proceed()
|
||||
}
|
||||
}
|
||||
case let .joinVoiceChat(peerId, invite):
|
||||
|
@ -920,18 +920,23 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
||||
handleResolvedUrl(.premiumMultiGift(reference: reference))
|
||||
} else if parsedUrl.host == "stars_topup" {
|
||||
var amount: Int64?
|
||||
var purpose: String?
|
||||
if let components = URLComponents(string: "/?" + query) {
|
||||
if let queryItems = components.queryItems {
|
||||
for queryItem in queryItems {
|
||||
if let value = queryItem.value {
|
||||
if queryItem.name == "amount" {
|
||||
if queryItem.name == "balance" {
|
||||
amount = Int64(value)
|
||||
} else if queryItem.name == "purpose" {
|
||||
purpose = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
handleResolvedUrl(.starsTopup(amount: amount))
|
||||
if let amount {
|
||||
handleResolvedUrl(.starsTopup(amount: amount, purpose: purpose))
|
||||
}
|
||||
} else if parsedUrl.host == "addlist" {
|
||||
if let components = URLComponents(string: "/?" + query) {
|
||||
var slug: String?
|
||||
|
@ -1650,8 +1650,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
return nil
|
||||
}
|
||||
|
||||
public func makeChatRecentActionsController(context: AccountContext, peer: Peer, adminPeerId: PeerId?) -> ViewController {
|
||||
return ChatRecentActionsController(context: context, peer: peer, adminPeerId: adminPeerId)
|
||||
public func makeChatRecentActionsController(context: AccountContext, peer: Peer, adminPeerId: PeerId?, starsState: StarsRevenueStats?) -> ViewController {
|
||||
return ChatRecentActionsController(context: context, peer: peer, adminPeerId: adminPeerId, starsState: starsState)
|
||||
}
|
||||
|
||||
public func presentContactsWarningSuppression(context: AccountContext, present: (ViewController, Any?) -> Void) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"app": "10.15",
|
||||
"app": "11.0",
|
||||
"xcode": "15.2",
|
||||
"bazel": "7.1.1",
|
||||
"macos": "13.0"
|
||||
|
Loading…
x
Reference in New Issue
Block a user