Merge commit 'f1753011e1e5ca79e4720288fd7a521344ef6373'

This commit is contained in:
Ali 2022-07-25 15:32:11 +02:00
commit 235482fea1
35 changed files with 473 additions and 340 deletions

Binary file not shown.

Binary file not shown.

View File

@ -7869,6 +7869,7 @@ Sorry for the inconvenience.";
"Premium.AnimatedEmoji" = "Animated Emoji";
"Premium.AnimatedEmojiInfo" = "Include animated emoji from different emoji sets in any message you send.";
"Premium.AnimatedEmojiStandaloneInfo" = "Include animated emoji from different emoji sets in any message you send.";
"ChatContextMenu.EmojiSetSingle" = "This message contains\n#[%@]() emoji.";
"ChatContextMenu.EmojiSet_1" = "This message contains emoji from [%@ pack]().";
@ -7886,6 +7887,12 @@ Sorry for the inconvenience.";
"EmojiPackActionInfo.ArchivedTitle" = "Emoji Archived";
"EmojiPackActionInfo.RemovedText" = "%@ is no longer in your emoji.";
"EmojiPackActionInfo.MultipleAddedText_1" = "%@ emoji pack has been added to your emoji.";
"EmojiPackActionInfo.MultipleAddedText_any" = "%@ emoji packs have been added to your emoji.";
"EmojiPackActionInfo.MultipleRemovedText_1" = "%@ emoji pack is no longer in your emoji.";
"EmojiPackActionInfo.MultipleRemovedText_any" = "%@ emoji packs are no longer in your emoji.";
"MaskPackActionInfo.RemovedTitle" = "Masks Removed";
"MaskPackActionInfo.ArchivedTitle" = "Masks Archived";
"MaskPackActionInfo.RemovedText" = "%@ is no longer in your masks.";
@ -7911,6 +7918,9 @@ Sorry for the inconvenience.";
"StickerSettings.EmojiContextInfo" = "If you archive an emoji set, you can quickly restore it later from the Archived Emoji section.";
"StickerPack.CopyLinks" = "Copy Links";
"Conversation.LinksCopied" = "Links copied to clipboard";
"StickersList.EmojiItem" = "Custom Emoji";
"StickersList.ArchivedEmojiItem" = "Archived Emoji";

View File

@ -560,6 +560,8 @@ public protocol ChatController: ViewController {
func beginMessageSearch(_ query: String)
func displayPromoAnnouncement(text: String)
func hintPlayNextOutgoingGift()
var isSendButtonVisible: Bool { get }
}

View File

@ -481,11 +481,13 @@ private func availablePaymentMethods(form: BotPaymentForm, current: BotCheckoutP
methods.append(.applePay)
hasApplePay = true
}
if let savedCredentials = form.savedCredentials {
for savedCredentials in form.savedCredentials {
if !methods.contains(.savedCredentials(savedCredentials)) {
methods.append(.savedCredentials(savedCredentials))
}
}
if !form.additionalPaymentMethods.isEmpty {
methods.append(contentsOf: form.additionalPaymentMethods.map { .other($0) })
}
@ -835,7 +837,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
}
var dismissImpl: (() -> Void)?
let canSave = paymentForm.canSaveCredentials || paymentForm.passwordMissing
let canSave = customUrl == nil && (paymentForm.canSaveCredentials || paymentForm.passwordMissing)
let controller = BotCheckoutNativeCardEntryController(context: strongSelf.context, provider: .stripe(additionalFields: additionalFields, publishableKey: publishableKey), completion: { method in
guard let strongSelf = self else {
return
@ -1106,7 +1108,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
strongSelf.botPeerValue = formAndValidatedInfo.botPeer
strongSelf.currentFormInfo = savedInfo
strongSelf.currentValidatedFormInfo = formAndValidatedInfo.validatedFormInfo
if let savedCredentials = formAndValidatedInfo.form.savedCredentials {
if let savedCredentials = formAndValidatedInfo.form.savedCredentials.first {
strongSelf.currentPaymentMethod = .savedCredentials(savedCredentials)
}
strongSelf.actionButton.isEnabled = true

View File

@ -471,7 +471,6 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
if self.animateInputField {
self.fromMessageTextNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
self.toMessageTextNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, removeOnCompletion: false)
self.textInputNode.isHidden = true
} else {
self.messageBackgroundNode.isHidden = true
self.fromMessageTextNode.isHidden = true
@ -526,6 +525,9 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
self.contentContainerNode.layer.animateSpring(from: NSValue(cgPoint: contentOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, initialVelocity: 0.0, damping: springDamping, additive: true)
Queue.mainQueue().after(0.01, {
if self.animateInputField {
self.textInputNode.isHidden = true
}
self.updateTextContents()
})
}

View File

@ -662,14 +662,17 @@ public class Window1 {
return
}
self.forceBadgeHidden = hidden
self.updateBadgeVisibility(layout: self.windowLayout)
self.updateBadgeVisibility()
}
private func updateBadgeVisibility(layout: WindowLayout) {
let badgeIsHidden = !self.deviceMetrics.hasTopNotch || self.forceBadgeHidden || layout.size.width > layout.size.height
private func updateBadgeVisibility() {
let badgeIsHidden = !self.deviceMetrics.hasTopNotch || self.forceBadgeHidden || self.windowLayout.size.width > self.windowLayout.size.height
if badgeIsHidden != self.badgeView.isHidden && !badgeIsHidden {
Queue.mainQueue().after(0.3) {
self.badgeView.isHidden = badgeIsHidden
Queue.mainQueue().after(0.4) {
let badgeShouldBeHidden = !self.deviceMetrics.hasTopNotch || self.forceBadgeHidden || self.windowLayout.size.width > self.windowLayout.size.height
if badgeShouldBeHidden == badgeIsHidden {
self.badgeView.isHidden = badgeIsHidden
}
}
} else {
self.badgeView.isHidden = badgeIsHidden
@ -1115,7 +1118,7 @@ public class Window1 {
}
if let image = self.badgeView.image {
self.updateBadgeVisibility(layout: self.windowLayout)
self.updateBadgeVisibility()
self.badgeView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((self.windowLayout.size.width - image.size.width) / 2.0), y: 6.0), size: image.size)
}
}

View File

@ -474,20 +474,22 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
}
let baseNavigationController = strongSelf.baseNavigationController()
baseNavigationController?.view.endEditing(true)
let controller = StickerPackScreen(context: context, mainStickerPack: packs[0], stickerPacks: packs, sendSticker: nil, actionPerformed: { info, items, action in
let animateInAsReplacement = false
switch action {
case .add:
topController?.present(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.StickerPackActionInfo_AddedTitle, text: presentationData.strings.StickerPackActionInfo_AddedText(info.title).string, undo: false, info: info, topItem: items.first, context: context), elevatedLayout: true, animateInAsReplacement: animateInAsReplacement, action: { _ in
return true
}), in: .window(.root))
case let .remove(positionInList):
topController?.present(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.StickerPackActionInfo_RemovedTitle, text: presentationData.strings.StickerPackActionInfo_RemovedText(info.title).string, undo: true, info: info, topItem: items.first, context: context), elevatedLayout: true, animateInAsReplacement: animateInAsReplacement, action: { action in
if case .undo = action {
let _ = context.engine.stickers.addStickerPackInteractively(info: info, items: items, positionInList: positionInList).start()
}
return true
}), in: .window(.root))
let controller = StickerPackScreen(context: context, mainStickerPack: packs[0], stickerPacks: packs, sendSticker: nil, actionPerformed: { actions in
if let (info, items, action) = actions.first {
let animateInAsReplacement = false
switch action {
case .add:
topController?.present(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.StickerPackActionInfo_AddedTitle, text: presentationData.strings.StickerPackActionInfo_AddedText(info.title).string, undo: false, info: info, topItem: items.first, context: context), elevatedLayout: true, animateInAsReplacement: animateInAsReplacement, action: { _ in
return true
}), in: .window(.root))
case let .remove(positionInList):
topController?.present(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.StickerPackActionInfo_RemovedTitle, text: presentationData.strings.StickerPackActionInfo_RemovedText(info.title).string, undo: true, info: info, topItem: items.first, context: context), elevatedLayout: true, animateInAsReplacement: animateInAsReplacement, action: { action in
if case .undo = action {
let _ = context.engine.stickers.addStickerPackInteractively(info: info, items: items, positionInList: positionInList).start()
}
return true
}), in: .window(.root))
}
}
})
(baseNavigationController?.topViewController as? ViewController)?.present(controller, in: .window(.root), with: nil)

View File

@ -2476,16 +2476,16 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
c.setItems(strongSelf.contextMenuSpeedItems() |> map { ContextController.Items(content: .list($0)) }, minHeight: nil)
})))
if #available(iOS 11.0, *) {
items.append(.action(ContextMenuActionItem(text: "AirPlay", textColor: .primary, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/AirPlay"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
f(.default)
guard let strongSelf = self else {
return
}
strongSelf.beginAirPlaySetup()
})))
}
// if #available(iOS 11.0, *) {
// items.append(.action(ContextMenuActionItem(text: "AirPlay", textColor: .primary, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/AirPlay"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
// f(.default)
// guard let strongSelf = self else {
// return
// }
// strongSelf.beginAirPlaySetup()
// })))
// }
if let (message, _, _) = strongSelf.contentInfo() {
for media in message.media {
@ -2667,20 +2667,22 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
}
let baseNavigationController = strongSelf.baseNavigationController()
baseNavigationController?.view.endEditing(true)
let controller = StickerPackScreen(context: strongSelf.context, mainStickerPack: packs[0], stickerPacks: Array(packs.prefix(1)), sendSticker: nil, actionPerformed: { info, items, action in
let animateInAsReplacement = false
switch action {
case .add:
topController?.present(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.StickerPackActionInfo_AddedTitle, text: presentationData.strings.StickerPackActionInfo_AddedText(info.title).string, undo: false, info: info, topItem: items.first, context: context), elevatedLayout: true, animateInAsReplacement: animateInAsReplacement, action: { _ in
return true
}), in: .window(.root))
case let .remove(positionInList):
topController?.present(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.StickerPackActionInfo_RemovedTitle, text: presentationData.strings.StickerPackActionInfo_RemovedText(info.title).string, undo: true, info: info, topItem: items.first, context: context), elevatedLayout: true, animateInAsReplacement: animateInAsReplacement, action: { action in
if case .undo = action {
let _ = context.engine.stickers.addStickerPackInteractively(info: info, items: items, positionInList: positionInList).start()
}
return true
}), in: .window(.root))
let controller = StickerPackScreen(context: strongSelf.context, mainStickerPack: packs[0], stickerPacks: Array(packs.prefix(1)), sendSticker: nil, actionPerformed: { actions in
if let (info, items, action) = actions.first {
let animateInAsReplacement = false
switch action {
case .add:
topController?.present(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.StickerPackActionInfo_AddedTitle, text: presentationData.strings.StickerPackActionInfo_AddedText(info.title).string, undo: false, info: info, topItem: items.first, context: context), elevatedLayout: true, animateInAsReplacement: animateInAsReplacement, action: { _ in
return true
}), in: .window(.root))
case let .remove(positionInList):
topController?.present(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.StickerPackActionInfo_RemovedTitle, text: presentationData.strings.StickerPackActionInfo_RemovedText(info.title).string, undo: true, info: info, topItem: items.first, context: context), elevatedLayout: true, animateInAsReplacement: animateInAsReplacement, action: { action in
if case .undo = action {
let _ = context.engine.stickers.addStickerPackInteractively(info: info, items: items, positionInList: positionInList).start()
}
return true
}), in: .window(.root))
}
}
}, dismissed: { [weak self] in
self?.isInteractingPromise.set(false)

View File

@ -694,7 +694,7 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
}
strongSelf.presentInGlobalOverlay?(UndoOverlayController(presentationData: strongSelf.presentationData, content: .stickersModified(title: strongSelf.presentationData.strings.StickerPackActionInfo_AddedTitle, text: strongSelf.presentationData.strings.StickerPackActionInfo_AddedText(info.title).string, undo: false, info: info, topItem: firstItem ?? items.first, context: strongSelf.context), elevatedLayout: false, action: { action in
if case .info = action {
(navigationController?.viewControllers.last as? ViewController)?.present(StickerPackScreen(context: context, mode: .settings, mainStickerPack: .id(id: info.id.id, accessHash: info.accessHash), stickerPacks: [], parentNavigationController: navigationController, actionPerformed: { _, _, _ in
(navigationController?.viewControllers.last as? ViewController)?.present(StickerPackScreen(context: context, mode: .settings, mainStickerPack: .id(id: info.id.id, accessHash: info.accessHash), stickerPacks: [], parentNavigationController: navigationController, actionPerformed: { _ in
}), in: .window(.root))
}
return true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -909,7 +909,7 @@ private final class DemoSheetContent: CombinedComponent {
decoration: .emoji
)),
title: strings.Premium_AnimatedEmoji,
text: strings.Premium_AnimatedEmojiInfo,
text: isStandalone ? strings.Premium_AnimatedEmojiStandaloneInfo : strings.Premium_AnimatedEmojiInfo,
textColor: textColor
)
)

View File

@ -145,7 +145,7 @@ private final class ProductGroupComponent: Component {
buttonView?.backgroundColor = component.selectionColor
} else {
UIView.animate(withDuration: 0.3, animations: {
buttonView?.backgroundColor = nil
buttonView?.backgroundColor = component.backgroundColor
})
}
}
@ -299,31 +299,44 @@ private final class GiftComponent: CombinedComponent {
transition: context.transition
)
let discount = discount.update(
component: MultilineTextComponent(
text: .plain(
NSAttributedString(
string: component.discount,
font: Font.with(size: 14.0, design: .round, weight: .semibold, traits: []),
textColor: .white
)
let discountSize: CGSize
if !component.discount.isEmpty {
let discount = discount.update(
component: MultilineTextComponent(
text: .plain(
NSAttributedString(
string: component.discount,
font: Font.with(size: 14.0, design: .round, weight: .semibold, traits: []),
textColor: .white
)
),
maximumNumberOfLines: 1
),
maximumNumberOfLines: 1
),
availableSize: context.availableSize,
transition: context.transition
)
availableSize: context.availableSize,
transition: context.transition
)
discountSize = CGSize(width: discount.size.width + 6.0, height: 18.0)
let discountSize = CGSize(width: discount.size.width + 6.0, height: 18.0)
let discountBackground = discountBackground.update(
component: RoundedRectangle(
color: component.accentColor,
cornerRadius: 5.0
),
availableSize: discountSize,
transition: context.transition
)
let discountBackground = discountBackground.update(
component: RoundedRectangle(
color: component.accentColor,
cornerRadius: 5.0
),
availableSize: discountSize,
transition: context.transition
)
context.add(discountBackground
.position(CGPoint(x: insets.left + discountSize.width / 2.0, y: insets.top + title.size.height + spacing + discountSize.height / 2.0))
)
context.add(discount
.position(CGPoint(x: insets.left + discountSize.width / 2.0, y: insets.top + title.size.height + spacing + discountSize.height / 2.0))
)
} else {
discountSize = CGSize(width: 0.0, height: 18.0)
}
let subtitle = subtitle.update(
component: MultilineTextComponent(
@ -359,17 +372,9 @@ private final class GiftComponent: CombinedComponent {
context.add(title
.position(CGPoint(x: insets.left + title.size.width / 2.0, y: insets.top + title.size.height / 2.0))
)
context.add(discountBackground
.position(CGPoint(x: insets.left + discountSize.width / 2.0, y: insets.top + title.size.height + spacing + discountSize.height / 2.0))
)
context.add(discount
.position(CGPoint(x: insets.left + discountSize.width / 2.0, y: insets.top + title.size.height + spacing + discountSize.height / 2.0))
)
context.add(subtitle
.position(CGPoint(x: insets.left + discountSize.width + 7.0 + subtitle.size.width / 2.0, y: insets.top + title.size.height + spacing + discountSize.height / 2.0))
.position(CGPoint(x: insets.left + (discountSize.width.isZero ? 0.0 : discountSize.width + 7.0) + subtitle.size.width / 2.0, y: insets.top + title.size.height + spacing + discountSize.height / 2.0))
)
let size = CGSize(width: context.availableSize.width, height: insets.top + title.size.height + spacing + subtitle.size.height + insets.bottom)
@ -510,13 +515,13 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
let context: AccountContext
let peer: EnginePeer?
let products: [InAppPurchaseManager.Product]?
let products: [PremiumGiftProduct]?
let selectedProductId: String?
let present: (ViewController) -> Void
let selectProduct: (String) -> Void
init(context: AccountContext, peer: EnginePeer?, products: [InAppPurchaseManager.Product]?, selectedProductId: String?, present: @escaping (ViewController) -> Void, selectProduct: @escaping (String) -> Void) {
init(context: AccountContext, peer: EnginePeer?, products: [PremiumGiftProduct]?, selectedProductId: String?, present: @escaping (ViewController) -> Void, selectProduct: @escaping (String) -> Void) {
self.context = context
self.peer = peer
self.products = products
@ -629,27 +634,27 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
var i = 0
if let products = component.products {
let shortestOptionPrice: Int64
if let product = products.last {
shortestOptionPrice = Int64(Float(product.storeProduct.priceCurrencyAndAmount.amount) / Float(product.months))
} else {
shortestOptionPrice = 1
}
for product in products {
let monthsCount: Int
let giftTitle: String
if product.months == 12 {
giftTitle = strings.Premium_Gift_Years(1)
} else {
giftTitle = strings.Premium_Gift_Months(product.months)
}
let discountValue = Int((1.0 - Float(product.storeProduct.priceCurrencyAndAmount.amount) / Float(product.months) / Float(shortestOptionPrice)) * 100.0)
let discount: String
switch product.id {
case "org.telegram.telegramPremium.twelveMonths":
giftTitle = strings.Premium_Gift_Years(1)
monthsCount = 12
discount = "-15%"
case "org.telegram.telegramPremium.sixMonths":
giftTitle = strings.Premium_Gift_Months(6)
monthsCount = 6
discount = "-10%"
case "org.telegram.telegramPremium.threeMonths":
giftTitle = strings.Premium_Gift_Months(3)
monthsCount = 3
discount = "-7%"
default:
giftTitle = ""
monthsCount = 1
discount = ""
if discountValue > 0 {
discount = "-\(discountValue)%"
} else {
discount = ""
}
items.append(ProductGroupComponent.Item(
@ -659,7 +664,7 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
GiftComponent(
title: giftTitle,
totalPrice: product.price,
perMonthPrice: strings.Premium_Gift_PricePerMonth(product.pricePerMonth(monthsCount)).string,
perMonthPrice: strings.Premium_Gift_PricePerMonth(product.pricePerMonth).string,
discount: discount,
selected: product.id == component.selectedProductId,
primaryTextColor: textColor,
@ -705,19 +710,42 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
}
}
private struct PremiumGiftProduct: Equatable {
let giftOption: CachedPremiumGiftOption
let storeProduct: InAppPurchaseManager.Product
var id: String {
return self.storeProduct.id
}
var months: Int32 {
return self.giftOption.months
}
var price: String {
return self.storeProduct.price
}
var pricePerMonth: String {
return self.storeProduct.pricePerMonth(Int(self.months))
}
}
private final class PremiumGiftScreenComponent: CombinedComponent {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
let context: AccountContext
let peerId: PeerId
let options: [CachedPremiumGiftOption]
let updateInProgress: (Bool) -> Void
let present: (ViewController) -> Void
let push: (ViewController) -> Void
let completion: (Int32) -> Void
init(context: AccountContext, peerId: PeerId, updateInProgress: @escaping (Bool) -> Void, present: @escaping (ViewController) -> Void, push: @escaping (ViewController) -> Void, completion: @escaping (Int32) -> Void) {
init(context: AccountContext, peerId: PeerId, options: [CachedPremiumGiftOption], updateInProgress: @escaping (Bool) -> Void, present: @escaping (ViewController) -> Void, push: @escaping (ViewController) -> Void, completion: @escaping (Int32) -> Void) {
self.context = context
self.peerId = peerId
self.options = options
self.updateInProgress = updateInProgress
self.present = present
self.push = push
@ -731,12 +759,16 @@ private final class PremiumGiftScreenComponent: CombinedComponent {
if lhs.peerId != rhs.peerId {
return false
}
if lhs.options != rhs.options {
return false
}
return true
}
final class State: ComponentState {
private let context: AccountContext
private let peerId: PeerId
private let options: [CachedPremiumGiftOption]
private let updateInProgress: (Bool) -> Void
private let present: (ViewController) -> Void
private let completion: (Int32) -> Void
@ -749,16 +781,17 @@ private final class PremiumGiftScreenComponent: CombinedComponent {
var inProgress = false
var peer: EnginePeer?
var products: [InAppPurchaseManager.Product]?
var products: [PremiumGiftProduct]?
var selectedProductId: String?
private var disposable: Disposable?
private var paymentDisposable = MetaDisposable()
private var activationDisposable = MetaDisposable()
init(context: AccountContext, peerId: PeerId, updateInProgress: @escaping (Bool) -> Void, present: @escaping (ViewController) -> Void, completion: @escaping (Int32) -> Void) {
init(context: AccountContext, peerId: PeerId, options: [CachedPremiumGiftOption], updateInProgress: @escaping (Bool) -> Void, present: @escaping (ViewController) -> Void, completion: @escaping (Int32) -> Void) {
self.context = context
self.peerId = peerId
self.options = options
self.updateInProgress = updateInProgress
self.present = present
self.completion = completion
@ -778,8 +811,18 @@ private final class PremiumGiftScreenComponent: CombinedComponent {
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
).start(next: { [weak self] products, peer in
if let strongSelf = self {
strongSelf.products = products.filter { !$0.isSubscription }.sorted(by: { $0.priceValue.compare($1.priceValue) == .orderedDescending })
strongSelf.selectedProductId = strongSelf.products?.first?.id
var gifts: [PremiumGiftProduct] = []
for option in strongSelf.options {
if let product = products.first(where: { $0.id == option.storeProductId }), !product.isSubscription {
gifts.append(PremiumGiftProduct(giftOption: option, storeProduct: product))
}
}
strongSelf.products = gifts
if strongSelf.selectedProductId == nil {
strongSelf.selectedProductId = strongSelf.products?.first?.id
}
strongSelf.peer = peer
strongSelf.updated(transition: .immediate)
}
@ -805,19 +848,8 @@ private final class PremiumGiftScreenComponent: CombinedComponent {
guard let product = self.products?.first(where: { $0.id == self.selectedProductId }) else {
return
}
let (currency, amount) = product.priceCurrencyAndAmount
let duration: Int32
switch product.id {
case "org.telegram.telegramPremium.twelveMonths":
duration = 12
case "org.telegram.telegramPremium.sixMonths":
duration = 6
case "org.telegram.telegramPremium.threeMonths":
duration = 3
default:
duration = 0
}
let (currency, amount) = product.storeProduct.priceCurrencyAndAmount
let duration = product.months
// addAppLogEvent(postbox: self.context.account.postbox, type: "premium.promo_screen_accept")
@ -829,7 +861,7 @@ private final class PremiumGiftScreenComponent: CombinedComponent {
|> deliverOnMainQueue).start(next: { [weak self] available in
if let strongSelf = self {
if available {
strongSelf.paymentDisposable.set((inAppPurchaseManager.buyProduct(product, targetPeerId: strongSelf.peerId)
strongSelf.paymentDisposable.set((inAppPurchaseManager.buyProduct(product.storeProduct, targetPeerId: strongSelf.peerId)
|> deliverOnMainQueue).start(next: { [weak self] status in
if let strongSelf = self, case .purchased = status {
strongSelf.activationDisposable.set((strongSelf.context.account.postbox.peerView(id: strongSelf.context.account.peerId)
@ -852,7 +884,7 @@ private final class PremiumGiftScreenComponent: CombinedComponent {
strongSelf.updated(transition: .immediate)
addAppLogEvent(postbox: strongSelf.context.account.postbox, type: "premium.promo_screen_fail")
// addAppLogEvent(postbox: strongSelf.context.account.postbox, type: "premium.promo_screen_fail")
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let errorText = presentationData.strings.Premium_Purchase_ErrorUnknown
@ -896,7 +928,7 @@ private final class PremiumGiftScreenComponent: CombinedComponent {
}
if let errorText = errorText {
addAppLogEvent(postbox: strongSelf.context.account.postbox, type: "premium.promo_screen_fail")
// addAppLogEvent(postbox: strongSelf.context.account.postbox, type: "premium.promo_screen_fail")
let alertController = textAlertController(context: strongSelf.context, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
strongSelf.present(alertController)
@ -919,7 +951,7 @@ private final class PremiumGiftScreenComponent: CombinedComponent {
}
func makeState() -> State {
return State(context: self.context, peerId: self.peerId, updateInProgress: self.updateInProgress, present: self.present, completion: self.completion)
return State(context: self.context, peerId: self.peerId, options: self.options, updateInProgress: self.updateInProgress, present: self.present, completion: self.completion)
}
static var body: Body {
@ -1242,6 +1274,7 @@ public final class PremiumGiftScreen: ViewControllerComponentContainer {
super.init(context: context, component: PremiumGiftScreenComponent(
context: context,
peerId: peerId,
options: options,
updateInProgress: { inProgress in
updateInProgressImpl?(inProgress)
},
@ -1278,6 +1311,12 @@ public final class PremiumGiftScreen: ViewControllerComponentContainer {
if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController {
var controllers = navigationController.viewControllers
controllers = controllers.filter { !($0 is PeerInfoScreen) && !($0 is PremiumGiftScreen) }
for controller in controllers.reversed() {
if let chatController = controller as? ChatController, case .peer(id: peerId) = chatController.chatLocation {
chatController.hintPlayNextOutgoingGift()
break
}
}
navigationController.setViewControllers(controllers, animated: true)
}
}

View File

@ -300,7 +300,7 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry {
case let .privacyHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .blockedPeers(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, icon: UIImage(bundleImageName: "Chat/Stickers/Blocked")?.precomposed(), title: text, label: value, sectionId: self.section, style: .blocks, action: {
return ItemListDisclosureItem(presentationData: presentationData, icon: UIImage(bundleImageName: "Settings/Menu/Blocked")?.precomposed(), title: text, label: value, sectionId: self.section, style: .blocks, action: {
arguments.openBlockedUsers()
})
case let .phoneNumberPrivacy(_, text, value):

View File

@ -1267,7 +1267,7 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
packs.insert(packReference, at: 0)
}
if let mainStickerPack = mainStickerPack {
presentControllerImpl?(StickerPackScreen(context: context, mode: .settings, mainStickerPack: mainStickerPack, stickerPacks: [mainStickerPack], parentNavigationController: controller?.navigationController as? NavigationController, actionPerformed: { info, items, action in
presentControllerImpl?(StickerPackScreen(context: context, mode: .settings, mainStickerPack: mainStickerPack, stickerPacks: [mainStickerPack], parentNavigationController: controller?.navigationController as? NavigationController, actionPerformed: { actions in
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
var animateInAsReplacement = false
if let navigationController = navigationControllerImpl?() {
@ -1278,31 +1278,33 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
}
}
}
switch action {
case .add:
navigationControllerImpl?()?.presentOverlay(controller: UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.StickerPackActionInfo_AddedTitle, text: presentationData.strings.StickerPackActionInfo_AddedText(info.title).string, undo: false, info: info, topItem: items.first, context: context), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in
return true
}))
case let .remove(positionInList):
let removedTitle: String
let removedText: String
if info.id.namespace == Namespaces.ItemCollection.CloudEmojiPacks {
removedTitle = presentationData.strings.EmojiPackActionInfo_RemovedTitle
removedText = presentationData.strings.EmojiPackActionInfo_RemovedText(info.title).string
} else if info.id.namespace == Namespaces.ItemCollection.CloudMaskPacks {
removedTitle = presentationData.strings.MaskPackActionInfo_RemovedTitle
removedText = presentationData.strings.MaskPackActionInfo_RemovedText(info.title).string
} else {
removedTitle = presentationData.strings.StickerPackActionInfo_RemovedTitle
removedText = presentationData.strings.StickerPackActionInfo_RemovedText(info.title).string
}
navigationControllerImpl?()?.presentOverlay(controller: UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: removedTitle, text: removedText, undo: true, info: info, topItem: items.first, context: context), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { action in
if case .undo = action {
let _ = context.engine.stickers.addStickerPackInteractively(info: info, items: items, positionInList: positionInList).start()
if let (info, items, action) = actions.first {
switch action {
case .add:
navigationControllerImpl?()?.presentOverlay(controller: UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.StickerPackActionInfo_AddedTitle, text: presentationData.strings.StickerPackActionInfo_AddedText(info.title).string, undo: false, info: info, topItem: items.first, context: context), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in
return true
}))
case let .remove(positionInList):
let removedTitle: String
let removedText: String
if info.id.namespace == Namespaces.ItemCollection.CloudEmojiPacks {
removedTitle = presentationData.strings.EmojiPackActionInfo_RemovedTitle
removedText = presentationData.strings.EmojiPackActionInfo_RemovedText(info.title).string
} else if info.id.namespace == Namespaces.ItemCollection.CloudMaskPacks {
removedTitle = presentationData.strings.MaskPackActionInfo_RemovedTitle
removedText = presentationData.strings.MaskPackActionInfo_RemovedText(info.title).string
} else {
removedTitle = presentationData.strings.StickerPackActionInfo_RemovedTitle
removedText = presentationData.strings.StickerPackActionInfo_RemovedText(info.title).string
}
return true
}))
navigationControllerImpl?()?.presentOverlay(controller: UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: removedTitle, text: removedText, undo: true, info: info, topItem: items.first, context: context), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { action in
if case .undo = action {
let _ = context.engine.stickers.addStickerPackInteractively(info: info, items: items, positionInList: positionInList).start()
}
return true
}))
}
}
}), nil)
}

View File

@ -192,7 +192,7 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
lockBackground.isUserInteractionEnabled = false
lockIconNode = ASImageNode()
lockIconNode.displaysAsynchronously = false
lockIconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/Lock"), color: .white)
lockIconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat List/PeerPremiumIcon"), color: .white)
let lockTintView = UIView()
lockTintView.backgroundColor = UIColor(rgb: 0x000000, alpha: 0.15)
@ -321,8 +321,8 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
}
if let lockBackground = self.lockBackground, let lockTintView = self.lockTintView, let lockIconNode = self.lockIconNode {
let lockSize = CGSize(width: 30.0, height: 30.0)
let lockBackgroundFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((bounds.width - lockSize.width) / 2.0), y: bounds.height - lockSize.height - 6.0), size: lockSize)
let lockSize = CGSize(width: 16.0, height: 16.0)
let lockBackgroundFrame = CGRect(origin: CGPoint(x: bounds.width - lockSize.width, y: bounds.height - lockSize.height), size: lockSize)
lockBackground.frame = lockBackgroundFrame
lockBackground.layer.cornerRadius = lockSize.width / 2.0
if #available(iOS 13.0, *) {
@ -330,7 +330,8 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
}
lockTintView.frame = CGRect(origin: CGPoint(), size: lockBackgroundFrame.size)
if let icon = lockIconNode.image {
lockIconNode.frame = CGRect(origin: CGPoint(x: lockBackgroundFrame.minX + floorToScreenPixels((lockBackgroundFrame.width - icon.size.width) / 2.0), y: lockBackgroundFrame.minY + floorToScreenPixels((lockBackgroundFrame.height - icon.size.height) / 2.0)), size: icon.size)
let iconSize = CGSize(width: icon.size.width - 4.0, height: icon.size.height - 4.0)
lockIconNode.frame = CGRect(origin: CGPoint(x: lockBackgroundFrame.minX + floorToScreenPixels((lockBackgroundFrame.width - iconSize.width) / 2.0), y: lockBackgroundFrame.minY + floorToScreenPixels((lockBackgroundFrame.height - iconSize.height) / 2.0)), size: iconSize)
}
}
}

View File

@ -586,7 +586,10 @@ private final class StickerPackContainer: ASDisplayNode {
strongSelf.controller?.present(shareController, in: .window(.root))
}
})))
items.append(.action(ContextMenuActionItem(text: strings.StickerPack_CopyLink, icon: { theme in
let copyTitle = self.currentStickerPacks.count > 1 ? strings.StickerPack_CopyLinks : strings.StickerPack_CopyLink
let copyText = self.currentStickerPacks.count > 1 ? strings.Conversation_LinksCopied : strings.Conversation_LinkCopied
items.append(.action(ContextMenuActionItem(text: copyTitle, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, f in
f(.default)
@ -595,7 +598,7 @@ private final class StickerPackContainer: ASDisplayNode {
if let strongSelf = self {
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
strongSelf.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
strongSelf.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: copyText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
}
})))
@ -629,14 +632,15 @@ private final class StickerPackContainer: ASDisplayNode {
})
}
} else {
var installedPacks: [(StickerPackCollectionInfo, [StickerPackItem], StickerPackScreenPerformedAction)] = []
for (info, items, isInstalled) in self.currentStickerPacks {
if !isInstalled {
installedPacks.append((info, items, .add))
let _ = self.context.engine.stickers.addStickerPackInteractively(info: info, items: items).start()
// if dismissed {
// actionPerformed?(info, items, .add)
// }
}
}
self.controller?.actionPerformed?(installedPacks)
}
self.requestDismiss()
} else if let (info, items, installed) = self.currentStickerPack {
@ -657,13 +661,13 @@ private final class StickerPackContainer: ASDisplayNode {
return
}
if dismissed {
actionPerformed?(info, items, .remove(positionInList: positionInList))
actionPerformed?([(info, items, .remove(positionInList: positionInList))])
}
})
} else {
let _ = self.context.engine.stickers.addStickerPackInteractively(info: info, items: items).start()
if dismissed {
actionPerformed?(info, items, .add)
actionPerformed?([(info, items, .add)])
}
}
} else {
@ -1217,7 +1221,6 @@ private final class StickerPackScreenNode: ViewControllerTracingNode {
super.didLoad()
self.dimNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimNodeTapGesture(_:))))
self.containerContainingNode.view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:))))
}
func updatePresentationData(_ presentationData: PresentationData) {
@ -1235,11 +1238,7 @@ private final class StickerPackScreenNode: ViewControllerTracingNode {
transition.updateFrame(node: self.containerContainingNode, frame: CGRect(origin: CGPoint(), size: layout.size))
let expandProgress: CGFloat = 1.0
// if self.stickerPacks.count == 1 {
// expandProgress = 1.0
// } else {
// expandProgress = self.containers[self.selectedStickerPackIndex]?.expandProgress ?? 0.0
// }
let scaledInset: CGFloat = 12.0
let scaledDistance: CGFloat = 4.0
let minScale = (layout.size.width - scaledInset * 2.0) / layout.size.width
@ -1247,108 +1246,106 @@ private final class StickerPackScreenNode: ViewControllerTracingNode {
let containerVerticalOffset: CGFloat = (1.0 - expandProgress) * scaledInset * 2.0
// for i in 0 ..< self.stickerPacks.count {
let i = 0
let indexOffset = i - self.selectedStickerPackIndex
var scaledOffset: CGFloat = 0.0
scaledOffset = -CGFloat(indexOffset) * (1.0 - expandProgress) * (scaledInset * 2.0) + CGFloat(indexOffset) * scaledDistance
if abs(indexOffset) <= 1 {
let containerTransition: ContainedViewLayoutTransition
let container: StickerPackContainer
var wasAdded = false
if let current = self.containers[i] {
containerTransition = transition
container = current
} else {
wasAdded = true
containerTransition = .immediate
let index = i
container = StickerPackContainer(index: index, context: context, presentationData: self.presentationData, stickerPacks: self.stickerPacks, decideNextAction: { [weak self] container, action in
guard let strongSelf = self, let layout = strongSelf.validLayout else {
return .dismiss
}
if index == strongSelf.stickerPacks.count - 1 {
return .dismiss
} else {
switch action {
case .add:
var allAdded = true
for _ in index + 1 ..< strongSelf.stickerPacks.count {
if let container = strongSelf.containers[index], let (_, _, installed) = container.currentStickerPack {
if !installed {
allAdded = false
}
} else {
let indexOffset = i - self.selectedStickerPackIndex
var scaledOffset: CGFloat = 0.0
scaledOffset = -CGFloat(indexOffset) * (1.0 - expandProgress) * (scaledInset * 2.0) + CGFloat(indexOffset) * scaledDistance
if abs(indexOffset) <= 1 {
let containerTransition: ContainedViewLayoutTransition
let container: StickerPackContainer
var wasAdded = false
if let current = self.containers[i] {
containerTransition = transition
container = current
} else {
wasAdded = true
containerTransition = .immediate
let index = i
container = StickerPackContainer(index: index, context: context, presentationData: self.presentationData, stickerPacks: self.stickerPacks, decideNextAction: { [weak self] container, action in
guard let strongSelf = self, let layout = strongSelf.validLayout else {
return .dismiss
}
if index == strongSelf.stickerPacks.count - 1 {
return .dismiss
} else {
switch action {
case .add:
var allAdded = true
for _ in index + 1 ..< strongSelf.stickerPacks.count {
if let container = strongSelf.containers[index], let (_, _, installed) = container.currentStickerPack {
if !installed {
allAdded = false
}
}
if allAdded {
return .dismiss
}
case .remove:
if strongSelf.stickerPacks.count == 1 {
return .dismiss
} else {
return .ignored
allAdded = false
}
}
}
strongSelf.selectedStickerPackIndex = strongSelf.selectedStickerPackIndex + 1
strongSelf.containerLayoutUpdated(layout, transition: .animated(duration: 0.3, curve: .spring))
return .navigatedNext
}, requestDismiss: { [weak self] in
self?.dismiss()
}, expandProgressUpdated: { [weak self] container, transition, expandTransition in
guard let strongSelf = self, let layout = strongSelf.validLayout else {
return
}
if index == strongSelf.selectedStickerPackIndex, let container = strongSelf.containers[strongSelf.selectedStickerPackIndex] {
let modalProgress = container.modalProgress
strongSelf.modalProgressUpdated(modalProgress, transition)
strongSelf.containerLayoutUpdated(layout, transition: expandTransition)
for (_, otherContainer) in strongSelf.containers {
if otherContainer !== container {
otherContainer.syncExpandProgress(expandScrollProgress: container.expandScrollProgress, expandProgress: container.expandProgress, modalProgress: container.modalProgress, transition: expandTransition)
}
if allAdded {
return .dismiss
}
case .remove:
if strongSelf.stickerPacks.count == 1 {
return .dismiss
} else {
return .ignored
}
}
}, presentInGlobalOverlay: presentInGlobalOverlay, sendSticker: sendSticker, openMention: openMention, controller: self.controller)
container.onReady = { [weak self] in
self?.onReady()
}
container.onLoading = { [weak self] in
self?.onLoading()
strongSelf.selectedStickerPackIndex = strongSelf.selectedStickerPackIndex + 1
strongSelf.containerLayoutUpdated(layout, transition: .animated(duration: 0.3, curve: .spring))
return .navigatedNext
}, requestDismiss: { [weak self] in
self?.dismiss()
}, expandProgressUpdated: { [weak self] container, transition, expandTransition in
guard let strongSelf = self, let layout = strongSelf.validLayout else {
return
}
container.onError = { [weak self] in
self?.onError()
}
self.containerContainingNode.addSubnode(container)
self.containers[i] = container
}
let containerFrame = CGRect(origin: CGPoint(x: CGFloat(indexOffset) * layout.size.width + self.relativeToSelectedStickerPackTransition + scaledOffset, y: containerVerticalOffset), size: layout.size)
containerTransition.updateFrame(node: container, frame: containerFrame, beginWithCurrentState: true)
containerTransition.updateSublayerTransformScaleAndOffset(node: container, scale: containerScale, offset: CGPoint(), beginWithCurrentState: true)
if container.validLayout?.0 != layout {
container.updateLayout(layout: layout, transition: containerTransition)
}
if wasAdded {
if let selectedContainer = self.containers[self.selectedStickerPackIndex] {
if selectedContainer !== container {
container.syncExpandProgress(expandScrollProgress: selectedContainer.expandScrollProgress, expandProgress: selectedContainer.expandProgress, modalProgress: selectedContainer.modalProgress, transition: .immediate)
if index == strongSelf.selectedStickerPackIndex, let container = strongSelf.containers[strongSelf.selectedStickerPackIndex] {
let modalProgress = container.modalProgress
strongSelf.modalProgressUpdated(modalProgress, transition)
strongSelf.containerLayoutUpdated(layout, transition: expandTransition)
for (_, otherContainer) in strongSelf.containers {
if otherContainer !== container {
otherContainer.syncExpandProgress(expandScrollProgress: container.expandScrollProgress, expandProgress: container.expandProgress, modalProgress: container.modalProgress, transition: expandTransition)
}
}
}
}, presentInGlobalOverlay: presentInGlobalOverlay, sendSticker: sendSticker, openMention: openMention, controller: self.controller)
container.onReady = { [weak self] in
self?.onReady()
}
} else {
if let container = self.containers[i] {
container.removeFromSupernode()
self.containers.removeValue(forKey: i)
container.onLoading = { [weak self] in
self?.onLoading()
}
container.onError = { [weak self] in
self?.onError()
}
self.containerContainingNode.addSubnode(container)
self.containers[i] = container
}
let containerFrame = CGRect(origin: CGPoint(x: CGFloat(indexOffset) * layout.size.width + self.relativeToSelectedStickerPackTransition + scaledOffset, y: containerVerticalOffset), size: layout.size)
containerTransition.updateFrame(node: container, frame: containerFrame, beginWithCurrentState: true)
containerTransition.updateSublayerTransformScaleAndOffset(node: container, scale: containerScale, offset: CGPoint(), beginWithCurrentState: true)
if container.validLayout?.0 != layout {
container.updateLayout(layout: layout, transition: containerTransition)
}
if wasAdded {
if let selectedContainer = self.containers[self.selectedStickerPackIndex] {
if selectedContainer !== container {
container.syncExpandProgress(expandScrollProgress: selectedContainer.expandScrollProgress, expandProgress: selectedContainer.expandProgress, modalProgress: selectedContainer.modalProgress, transition: .immediate)
}
}
}
// }
} else {
if let container = self.containers[i] {
container.removeFromSupernode()
self.containers.removeValue(forKey: i)
}
}
if firstTime {
if !self.containers.isEmpty {
@ -1512,7 +1509,7 @@ public final class StickerPackScreenImpl: ViewController {
}
public var dismissed: (() -> Void)?
public var actionPerformed: ((StickerPackCollectionInfo, [StickerPackItem], StickerPackScreenPerformedAction) -> Void)?
public var actionPerformed: (([(StickerPackCollectionInfo, [StickerPackItem], StickerPackScreenPerformedAction)]) -> Void)?
private let _ready = Promise<Bool>()
override public var ready: Promise<Bool> {
@ -1527,7 +1524,7 @@ public final class StickerPackScreenImpl: ViewController {
let animationCache: AnimationCache
let animationRenderer: MultiAnimationRenderer
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, stickerPacks: [StickerPackReference], selectedStickerPackIndex: Int = 0, parentNavigationController: NavigationController? = nil, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)? = nil, actionPerformed: ((StickerPackCollectionInfo, [StickerPackItem], StickerPackScreenPerformedAction) -> Void)? = nil) {
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, stickerPacks: [StickerPackReference], selectedStickerPackIndex: Int = 0, parentNavigationController: NavigationController? = nil, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)? = nil, actionPerformed: (([(StickerPackCollectionInfo, [StickerPackItem], StickerPackScreenPerformedAction)]) -> Void)? = nil) {
self.context = context
self.presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
self.stickerPacks = stickerPacks
@ -1706,7 +1703,7 @@ public enum StickerPackScreenPerformedAction {
case remove(positionInList: Int)
}
public func StickerPackScreen(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, mode: StickerPackPreviewControllerMode = .default, mainStickerPack: StickerPackReference, stickerPacks: [StickerPackReference], parentNavigationController: NavigationController? = nil, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)? = nil, actionPerformed: ((StickerPackCollectionInfo, [StickerPackItem], StickerPackScreenPerformedAction) -> Void)? = nil, dismissed: (() -> Void)? = nil) -> ViewController {
public func StickerPackScreen(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, mode: StickerPackPreviewControllerMode = .default, mainStickerPack: StickerPackReference, stickerPacks: [StickerPackReference], parentNavigationController: NavigationController? = nil, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)? = nil, actionPerformed: (([(StickerPackCollectionInfo, [StickerPackItem], StickerPackScreenPerformedAction)]) -> Void)? = nil, dismissed: (() -> Void)? = nil) -> ViewController {
//let stickerPacks = [mainStickerPack]
let controller = StickerPackScreenImpl(context: context, stickerPacks: stickerPacks, selectedStickerPackIndex: stickerPacks.firstIndex(of: mainStickerPack) ?? 0, parentNavigationController: parentNavigationController, sendSticker: sendSticker, actionPerformed: actionPerformed)
controller.dismissed = dismissed

View File

@ -1006,7 +1006,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[136574537] = { return Api.messages.VotesList.parse_votesList($0) }
dict[1042605427] = { return Api.payments.BankCardData.parse_bankCardData($0) }
dict[-1362048039] = { return Api.payments.ExportedInvoice.parse_exportedInvoice($0) }
dict[1288001087] = { return Api.payments.PaymentForm.parse_paymentForm($0) }
dict[-1610250415] = { return Api.payments.PaymentForm.parse_paymentForm($0) }
dict[1891958275] = { return Api.payments.PaymentReceipt.parse_paymentReceipt($0) }
dict[1314881805] = { return Api.payments.PaymentResult.parse_paymentResult($0) }
dict[-666824391] = { return Api.payments.PaymentResult.parse_paymentVerificationNeeded($0) }

View File

@ -728,13 +728,13 @@ public extension Api.payments {
}
public extension Api.payments {
enum PaymentForm: TypeConstructorDescription {
case paymentForm(flags: Int32, formId: Int64, botId: Int64, title: String, description: String, photo: Api.WebDocument?, invoice: Api.Invoice, providerId: Int64, url: String, nativeProvider: String?, nativeParams: Api.DataJSON?, additionalMethods: [Api.PaymentFormMethod]?, savedInfo: Api.PaymentRequestedInfo?, savedCredentials: Api.PaymentSavedCredentials?, users: [Api.User])
case paymentForm(flags: Int32, formId: Int64, botId: Int64, title: String, description: String, photo: Api.WebDocument?, invoice: Api.Invoice, providerId: Int64, url: String, nativeProvider: String?, nativeParams: Api.DataJSON?, additionalMethods: [Api.PaymentFormMethod]?, savedInfo: Api.PaymentRequestedInfo?, savedCredentials: [Api.PaymentSavedCredentials]?, users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .paymentForm(let flags, let formId, let botId, let title, let description, let photo, let invoice, let providerId, let url, let nativeProvider, let nativeParams, let additionalMethods, let savedInfo, let savedCredentials, let users):
if boxed {
buffer.appendInt32(1288001087)
buffer.appendInt32(-1610250415)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(formId, buffer: buffer, boxed: false)
@ -753,7 +753,11 @@ public extension Api.payments {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 0) != 0 {savedInfo!.serialize(buffer, true)}
if Int(flags) & Int(1 << 1) != 0 {savedCredentials!.serialize(buffer, true)}
if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(savedCredentials!.count))
for item in savedCredentials! {
item.serialize(buffer, true)
}}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
@ -807,9 +811,9 @@ public extension Api.payments {
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
_13 = Api.parse(reader, signature: signature) as? Api.PaymentRequestedInfo
} }
var _14: Api.PaymentSavedCredentials?
if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() {
_14 = Api.parse(reader, signature: signature) as? Api.PaymentSavedCredentials
var _14: [Api.PaymentSavedCredentials]?
if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() {
_14 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PaymentSavedCredentials.self)
} }
var _15: [Api.User]?
if let _ = reader.readInt32() {

View File

@ -64,7 +64,7 @@ private final class PendingUpdateMessageManagerImpl {
}
}
func add(messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: TelegramMediaFile], disableUrlPreview: Bool) {
func add(messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: Media], disableUrlPreview: Bool) {
if let context = self.contexts[messageId] {
self.contexts.removeValue(forKey: messageId)
context.disposable.dispose()
@ -163,7 +163,7 @@ public final class PendingUpdateMessageManager {
})
}
public func add(messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: TelegramMediaFile], disableUrlPreview: Bool = false) {
public func add(messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: Media], disableUrlPreview: Bool = false) {
self.impl.with { impl in
impl.add(messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview)
}

View File

@ -27,11 +27,11 @@ public enum RequestEditMessageError {
case invalidGrouping
}
func _internal_requestEditMessage(account: Account, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: TelegramMediaFile], disableUrlPreview: Bool = false, scheduleTime: Int32? = nil) -> Signal<RequestEditMessageResult, RequestEditMessageError> {
func _internal_requestEditMessage(account: Account, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: Media], disableUrlPreview: Bool = false, scheduleTime: Int32? = nil) -> Signal<RequestEditMessageResult, RequestEditMessageError> {
return requestEditMessage(postbox: account.postbox, network: account.network, stateManager: account.stateManager, transformOutgoingMessageMedia: account.transformOutgoingMessageMedia, messageMediaPreuploadManager: account.messageMediaPreuploadManager, mediaReferenceRevalidationContext: account.mediaReferenceRevalidationContext, messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime)
}
func requestEditMessage(postbox: Postbox, network: Network, stateManager: AccountStateManager, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: TelegramMediaFile], disableUrlPreview: Bool, scheduleTime: Int32?) -> Signal<RequestEditMessageResult, RequestEditMessageError> {
func requestEditMessage(postbox: Postbox, network: Network, stateManager: AccountStateManager, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: Media], disableUrlPreview: Bool, scheduleTime: Int32?) -> Signal<RequestEditMessageResult, RequestEditMessageError> {
return requestEditMessageInternal(postbox: postbox, network: network, stateManager: stateManager, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, mediaReferenceRevalidationContext: mediaReferenceRevalidationContext, messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime, forceReupload: false)
|> `catch` { error -> Signal<RequestEditMessageResult, RequestEditMessageInternalError> in
if case .invalidReference = error {
@ -50,7 +50,7 @@ func requestEditMessage(postbox: Postbox, network: Network, stateManager: Accoun
}
}
private func requestEditMessageInternal(postbox: Postbox, network: Network, stateManager: AccountStateManager, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: TelegramMediaFile], disableUrlPreview: Bool, scheduleTime: Int32?, forceReupload: Bool) -> Signal<RequestEditMessageResult, RequestEditMessageInternalError> {
private func requestEditMessageInternal(postbox: Postbox, network: Network, stateManager: AccountStateManager, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: Media], disableUrlPreview: Bool, scheduleTime: Int32?, forceReupload: Bool) -> Signal<RequestEditMessageResult, RequestEditMessageInternalError> {
let uploadedMedia: Signal<PendingMessageUploadedContentResult?, NoError>
switch media {
case .keep:

View File

@ -85,7 +85,7 @@ public extension TelegramEngine {
return _internal_clearAuthorHistory(account: self.account, peerId: peerId, memberId: memberId)
}
public func requestEditMessage(messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: TelegramMediaFile], disableUrlPreview: Bool = false, scheduleTime: Int32? = nil) -> Signal<RequestEditMessageResult, RequestEditMessageError> {
public func requestEditMessage(messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: Media], disableUrlPreview: Bool = false, scheduleTime: Int32? = nil) -> Signal<RequestEditMessageResult, RequestEditMessageError> {
return _internal_requestEditMessage(account: self.account, messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime)
}

View File

@ -119,7 +119,7 @@ public struct BotPaymentForm : Equatable {
public let url: String
public let nativeProvider: BotPaymentNativeProvider?
public let savedInfo: BotPaymentRequestedInfo?
public let savedCredentials: BotPaymentSavedCredentials?
public let savedCredentials: [BotPaymentSavedCredentials]
public let additionalPaymentMethods: [BotPaymentMethod]
}
@ -304,14 +304,13 @@ func _internal_fetchBotPaymentForm(postbox: Postbox, network: Network, source: B
}
}
let parsedSavedInfo = savedInfo.flatMap(BotPaymentRequestedInfo.init)
var parsedSavedCredentials: BotPaymentSavedCredentials?
if let savedCredentials = savedCredentials {
let parsedSavedCredentials = savedCredentials?.map({ savedCredentials -> BotPaymentSavedCredentials in
switch savedCredentials {
case let .paymentSavedCredentialsCard(id, title):
parsedSavedCredentials = .card(id: id, title: title)
return .card(id: id, title: title)
}
}
}) ?? []
let additionalPaymentMethods = additionalMethods?.map({ BotPaymentMethod(apiPaymentFormMethod: $0) }) ?? []
return BotPaymentForm(id: id, canSaveCredentials: (flags & (1 << 2)) != 0, passwordMissing: (flags & (1 << 3)) != 0, invoice: parsedInvoice, paymentBotId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId)), providerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(providerId)), url: url, nativeProvider: parsedNativeProvider, savedInfo: parsedSavedInfo, savedCredentials: parsedSavedCredentials, additionalPaymentMethods: additionalPaymentMethods)
}

View File

@ -1093,7 +1093,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var disableTransitionAnimations = false
var actionsSignal: Signal<ContextController.Items, NoError> = .single(actions)
if actions.tip == nil, let entitiesAttribute = message.textEntitiesAttribute {
if let entitiesAttribute = message.textEntitiesAttribute {
var emojiFileIds: [Int64] = []
for entity in entitiesAttribute.entities {
if case let .CustomEmoji(_, fileId) = entity.type {
@ -1128,7 +1128,36 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return
}
strongSelf.chatDisplayNode.dismissTextInput()
let controller = StickerPackScreen(context: context, updatedPresentationData: strongSelf.updatedPresentationData, mainStickerPack: packReference, stickerPacks: Array(packReferences), parentNavigationController: strongSelf.effectiveNavigationController)
let presentationData = strongSelf.presentationData
let controller = StickerPackScreen(context: context, updatedPresentationData: strongSelf.updatedPresentationData, mainStickerPack: packReference, stickerPacks: Array(packReferences), parentNavigationController: strongSelf.effectiveNavigationController, actionPerformed: { [weak self] actions in
guard let strongSelf = self else {
return
}
if actions.count > 1, let first = actions.first {
if case .add = first.2 {
strongSelf.presentInGlobalOverlay(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.EmojiPackActionInfo_AddedTitle, text: presentationData.strings.EmojiPackActionInfo_MultipleAddedText(Int32(actions.count)), undo: false, info: first.0, topItem: first.1.first, context: context), elevatedLayout: true, animateInAsReplacement: false, action: { _ in
return true
}))
}
} else if let (info, items, action) = actions.first {
let isEmoji = info.id.namespace == Namespaces.ItemCollection.CloudEmojiPacks
switch action {
case .add:
strongSelf.presentInGlobalOverlay(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: isEmoji ? presentationData.strings.EmojiPackActionInfo_AddedTitle : presentationData.strings.StickerPackActionInfo_AddedTitle, text: isEmoji ? presentationData.strings.EmojiPackActionInfo_AddedText(info.title).string : presentationData.strings.StickerPackActionInfo_AddedText(info.title).string, undo: false, info: info, topItem: items.first, context: context), elevatedLayout: true, animateInAsReplacement: false, action: { _ in
return true
}))
case let .remove(positionInList):
strongSelf.presentInGlobalOverlay(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: isEmoji ? presentationData.strings.EmojiPackActionInfo_RemovedTitle : presentationData.strings.StickerPackActionInfo_RemovedTitle, text: isEmoji ? presentationData.strings.EmojiPackActionInfo_RemovedText(info.title).string : presentationData.strings.StickerPackActionInfo_RemovedText(info.title).string, undo: true, info: info, topItem: items.first, context: context), elevatedLayout: true, animateInAsReplacement: false, action: { action in
if case .undo = action {
let _ = context.engine.stickers.addStickerPackInteractively(info: info, items: items, positionInList: positionInList).start()
}
return true
}))
}
}
})
strongSelf.present(controller, in: .window(.root))
}
@ -9412,7 +9441,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} else {
canSendMedia = true
}
if canSendMedia {
if canSendMedia && self.presentationInterfaceState.voiceMessagesAvailable {
let _ = (ApplicationSpecificNotice.getChatMediaMediaRecordingTips(accountManager: self.context.sharedContext.accountManager)
|> deliverOnMainQueue).start(next: { [weak self] counter in
guard let strongSelf = self else {
@ -16304,6 +16333,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})
}
public func hintPlayNextOutgoingGift() {
self.controllerInteraction?.playNextOutgoingGift = true
}
private var effectiveNavigationController: NavigationController? {
if let navigationController = self.navigationController as? NavigationController {
return navigationController

View File

@ -160,6 +160,7 @@ public final class ChatControllerInteraction {
var currentMessageWithLoadingReplyThread: MessageId?
var updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
let presentationContext: ChatPresentationContext
var playNextOutgoingGift: Bool = false
init(
openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool,

View File

@ -214,6 +214,9 @@ class ChatMessageBubbleContentNode: ASDisplayNode {
func applyAbsoluteOffsetSpring(value: CGFloat, duration: Double, damping: CGFloat) {
}
func unreadMessageRangeUpdated() {
}
func reactionTargetView(value: String) -> UIView? {
return nil
}

View File

@ -3975,6 +3975,12 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
return nil
}
override func unreadMessageRangeUpdated() {
for contentNode in self.contentNodes {
contentNode.unreadMessageRangeUpdated()
}
}
func animateQuizInvalidOptionSelected() {
if let supernode = self.supernode, let subnodes = supernode.subnodes {
for i in 0 ..< subnodes.count {

View File

@ -41,8 +41,6 @@ class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
private var absoluteRect: (CGRect, CGSize)?
private var isPlaying: Bool = false
private var wasPending: Bool = false
private var didChangeFromPendingToSent: Bool = false
override var visibility: ListViewItemNodeVisibility {
didSet {
@ -165,9 +163,9 @@ class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
duration = item.presentationData.strings.Notification_PremiumGift_Subtitle(item.presentationData.strings.Notification_PremiumGift_Months(months)).string
switch months {
case 12:
animationName = "Gift2"
animationName = "Gift12"
case 6:
animationName = "Gift1"
animationName = "Gift6"
case 3:
animationName = "Gift3"
default:
@ -227,13 +225,7 @@ class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
strongSelf.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: animationName), width: 384, height: 384, playbackMode: .still(.end), mode: .direct(cachePathPrefix: nil))
}
strongSelf.item = item
if item.message.id.namespace == Namespaces.Message.Local || item.message.id.namespace == Namespaces.Message.ScheduledLocal {
strongSelf.wasPending = true
}
if strongSelf.wasPending && (item.message.id.namespace != Namespaces.Message.Local && item.message.id.namespace != Namespaces.Message.ScheduledLocal) {
strongSelf.didChangeFromPendingToSent = true
}
strongSelf.updateVisibility()
strongSelf.backgroundColorNode.backgroundColor = selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper)
@ -416,6 +408,10 @@ class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
}
}
override func unreadMessageRangeUpdated() {
self.updateVisibility()
}
private func updateVisibility() {
guard let item = self.item else {
return
@ -430,12 +426,16 @@ class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
if isPlaying {
var alreadySeen = true
if let unreadRange = item.controllerInteraction.unreadMessageRange[UnreadMessageRangeKey(peerId: item.message.id.peerId, namespace: item.message.id.namespace)] {
if unreadRange.contains(item.message.id.id) {
if !item.controllerInteraction.seenOneTimeAnimatedMedia.contains(item.message.id) {
if item.message.flags.contains(.Incoming) {
if let unreadRange = item.controllerInteraction.unreadMessageRange[UnreadMessageRangeKey(peerId: item.message.id.peerId, namespace: item.message.id.namespace)] {
if unreadRange.contains(item.message.id.id) {
alreadySeen = false
}
}
} else {
if item.controllerInteraction.playNextOutgoingGift && !item.controllerInteraction.seenOneTimeAnimatedMedia.contains(item.message.id) {
alreadySeen = false
}
}
if !item.controllerInteraction.seenOneTimeAnimatedMedia.contains(item.message.id) {
@ -444,7 +444,9 @@ class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
}
if !alreadySeen {
item.controllerInteraction.animateDiceSuccess(false, true)
Queue.mainQueue().after(1.0) {
item.controllerInteraction.animateDiceSuccess(false, true)
}
}
}
}

View File

@ -363,7 +363,7 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
let colorKeys = ["__allcolors__"]
var colors: [String: UIColor] = [:]
for colorKey in colorKeys {
colors[colorKey] = self.theme.chat.inputPanel.panelControlColor
colors[colorKey] = self.theme.chat.inputPanel.panelControlColor.blitOver(self.theme.chat.inputPanel.inputBackgroundColor, alpha: 1.0)
}
let _ = animationView.update(
@ -497,8 +497,11 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
micDecoration.isHidden = false
micDecoration.startAnimating()
self.animationView.view?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
self.animationView.view?.layer.animateScale(from: 1.0, to: 0.3, duration: 0.15, removeOnCompletion: false)
let transition = ContainedViewLayoutTransition.animated(duration: 0.15, curve: .easeInOut)
if let layer = self.animationView.view?.layer {
transition.updateAlpha(layer: layer, alpha: 0.0)
transition.updateTransformScale(layer: layer, scale: 0.3)
}
}
override func animateOut(_ toSmallSize: Bool) {
@ -510,8 +513,11 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
micDecoration.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.03, delay: 0.15, removeOnCompletion: false)
} else {
micDecoration.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.18, removeOnCompletion: false)
self.animationView.view?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, removeOnCompletion: false)
self.animationView.view?.layer.animateScale(from: 0.3, to: 1.0, duration: 0.15, removeOnCompletion: false)
let transition = ContainedViewLayoutTransition.animated(duration: 0.15, curve: .easeInOut)
if let layer = self.animationView.view?.layer {
transition.updateAlpha(layer: layer, alpha: 1.0)
transition.updateTransformScale(layer: layer, scale: 1.0)
}
}
}

View File

@ -78,31 +78,40 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
params.navigationController?.pushViewController(controller)
return true
case let .stickerPack(reference):
let controller = StickerPackScreen(context: params.context, updatedPresentationData: params.updatedPresentationData, mainStickerPack: reference, stickerPacks: [reference], parentNavigationController: params.navigationController, sendSticker: params.sendSticker, actionPerformed: { info, items, action in
let isEmoji = info.id.namespace == Namespaces.ItemCollection.CloudEmojiPacks
let controller = StickerPackScreen(context: params.context, updatedPresentationData: params.updatedPresentationData, mainStickerPack: reference, stickerPacks: [reference], parentNavigationController: params.navigationController, sendSticker: params.sendSticker, actionPerformed: { actions in
let presentationData = params.context.sharedContext.currentPresentationData.with { $0 }
var animateInAsReplacement = false
if let navigationController = params.navigationController {
for controller in navigationController.overlayControllers {
if let controller = controller as? UndoOverlayController {
controller.dismissWithCommitActionAndReplacementAnimation()
animateInAsReplacement = true
if actions.count > 1, let first = actions.first {
if case .add = first.2 {
params.navigationController?.presentOverlay(controller: UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.EmojiPackActionInfo_AddedTitle, text: presentationData.strings.EmojiPackActionInfo_MultipleAddedText(Int32(actions.count)), undo: false, info: first.0, topItem: first.1.first, context: params.context), elevatedLayout: true, animateInAsReplacement: false, action: { _ in
return true
}))
}
} else if let (info, items, action) = actions.first {
let isEmoji = info.id.namespace == Namespaces.ItemCollection.CloudEmojiPacks
var animateInAsReplacement = false
if let navigationController = params.navigationController {
for controller in navigationController.overlayControllers {
if let controller = controller as? UndoOverlayController {
controller.dismissWithCommitActionAndReplacementAnimation()
animateInAsReplacement = true
}
}
}
}
switch action {
case .add:
params.navigationController?.presentOverlay(controller: UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: isEmoji ? presentationData.strings.EmojiPackActionInfo_AddedTitle : presentationData.strings.StickerPackActionInfo_AddedTitle, text: isEmoji ? presentationData.strings.EmojiPackActionInfo_AddedText(info.title).string : presentationData.strings.StickerPackActionInfo_AddedText(info.title).string, undo: false, info: info, topItem: items.first, context: params.context), elevatedLayout: true, animateInAsReplacement: animateInAsReplacement, action: { _ in
return true
}))
case let .remove(positionInList):
params.navigationController?.presentOverlay(controller: UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: isEmoji ? presentationData.strings.EmojiPackActionInfo_RemovedTitle : presentationData.strings.StickerPackActionInfo_RemovedTitle, text: isEmoji ? presentationData.strings.EmojiPackActionInfo_RemovedText(info.title).string : presentationData.strings.StickerPackActionInfo_RemovedText(info.title).string, undo: true, info: info, topItem: items.first, context: params.context), elevatedLayout: true, animateInAsReplacement: animateInAsReplacement, action: { action in
if case .undo = action {
let _ = params.context.engine.stickers.addStickerPackInteractively(info: info, items: items, positionInList: positionInList).start()
}
return true
}))
switch action {
case .add:
params.navigationController?.presentOverlay(controller: UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: isEmoji ? presentationData.strings.EmojiPackActionInfo_AddedTitle : presentationData.strings.StickerPackActionInfo_AddedTitle, text: isEmoji ? presentationData.strings.EmojiPackActionInfo_AddedText(info.title).string : presentationData.strings.StickerPackActionInfo_AddedText(info.title).string, undo: false, info: info, topItem: items.first, context: params.context), elevatedLayout: true, animateInAsReplacement: animateInAsReplacement, action: { _ in
return true
}))
case let .remove(positionInList):
params.navigationController?.presentOverlay(controller: UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: isEmoji ? presentationData.strings.EmojiPackActionInfo_RemovedTitle : presentationData.strings.StickerPackActionInfo_RemovedTitle, text: isEmoji ? presentationData.strings.EmojiPackActionInfo_RemovedText(info.title).string : presentationData.strings.StickerPackActionInfo_RemovedText(info.title).string, undo: true, info: info, topItem: items.first, context: params.context), elevatedLayout: true, animateInAsReplacement: animateInAsReplacement, action: { action in
if case .undo = action {
let _ = params.context.engine.stickers.addStickerPackInteractively(info: info, items: items, positionInList: positionInList).start()
}
return true
}))
}
}
})
params.dismissInput()

View File

@ -166,21 +166,29 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
case let .stickerPack(name, _):
dismissInput()
let controller = StickerPackScreen(context: context, updatedPresentationData: updatedPresentationData, mainStickerPack: .name(name), stickerPacks: [.name(name)], parentNavigationController: navigationController, sendSticker: sendSticker, actionPerformed: { info, items, action in
let isEmoji = info.id.namespace == Namespaces.ItemCollection.CloudEmojiPacks
switch action {
case .add:
present(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: isEmoji ? presentationData.strings.EmojiPackActionInfo_AddedTitle : presentationData.strings.StickerPackActionInfo_AddedTitle, text: isEmoji ? presentationData.strings.EmojiPackActionInfo_AddedText(info.title).string : presentationData.strings.StickerPackActionInfo_AddedText(info.title).string, undo: false, info: info, topItem: items.first, context: context), elevatedLayout: true, animateInAsReplacement: false, action: { _ in
return true
}), nil)
case let .remove(positionInList):
present(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: isEmoji ? presentationData.strings.EmojiPackActionInfo_RemovedTitle : presentationData.strings.StickerPackActionInfo_RemovedTitle, text: isEmoji ? presentationData.strings.EmojiPackActionInfo_RemovedText(info.title).string : presentationData.strings.StickerPackActionInfo_RemovedText(info.title).string, undo: true, info: info, topItem: items.first, context: context), elevatedLayout: true, animateInAsReplacement: false, action: { action in
if case .undo = action {
let _ = context.engine.stickers.addStickerPackInteractively(info: info, items: items, positionInList: positionInList).start()
}
return true
}), nil)
let controller = StickerPackScreen(context: context, updatedPresentationData: updatedPresentationData, mainStickerPack: .name(name), stickerPacks: [.name(name)], parentNavigationController: navigationController, sendSticker: sendSticker, actionPerformed: { actions in
if actions.count > 1, let first = actions.first {
if case .add = first.2 {
present(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.EmojiPackActionInfo_AddedTitle, text: presentationData.strings.EmojiPackActionInfo_MultipleAddedText(Int32(actions.count)), undo: false, info: first.0, topItem: first.1.first, context: context), elevatedLayout: true, animateInAsReplacement: false, action: { _ in
return true
}), nil)
}
} else if let (info, items, action) = actions.first {
let isEmoji = info.id.namespace == Namespaces.ItemCollection.CloudEmojiPacks
switch action {
case .add:
present(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: isEmoji ? presentationData.strings.EmojiPackActionInfo_AddedTitle : presentationData.strings.StickerPackActionInfo_AddedTitle, text: isEmoji ? presentationData.strings.EmojiPackActionInfo_AddedText(info.title).string : presentationData.strings.StickerPackActionInfo_AddedText(info.title).string, undo: false, info: info, topItem: items.first, context: context), elevatedLayout: true, animateInAsReplacement: false, action: { _ in
return true
}), nil)
case let .remove(positionInList):
present(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: isEmoji ? presentationData.strings.EmojiPackActionInfo_RemovedTitle : presentationData.strings.StickerPackActionInfo_RemovedTitle, text: isEmoji ? presentationData.strings.EmojiPackActionInfo_RemovedText(info.title).string : presentationData.strings.StickerPackActionInfo_RemovedText(info.title).string, undo: true, info: info, topItem: items.first, context: context), elevatedLayout: true, animateInAsReplacement: false, action: { action in
if case .undo = action {
let _ = context.engine.stickers.addStickerPackInteractively(info: info, items: items, positionInList: positionInList).start()
}
return true
}), nil)
}
}
})
present(controller, nil)

View File

@ -1,5 +1,5 @@
{
"app": "8.8.3",
"app": "8.9",
"bazel": "5.1.0",
"xcode": "13.4.1"
}