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
fed338985d
commit
2effcb42b7
@ -14032,3 +14032,5 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Privacy.Gifts.PremiumToast.Text" = "Subscribe to **Telegram Premium** to use this setting.";
|
||||
"Privacy.Gifts.PremiumToast.Action" = "Open";
|
||||
|
||||
"Gift.Send.ErrorDisallowed" = "**%@** doesn't accept this kind of gifts.";
|
||||
|
@ -1059,7 +1059,7 @@ public protocol SharedAccountContext: AnyObject {
|
||||
func makePremiumLimitController(context: AccountContext, subject: PremiumLimitSubject, count: Int32, forceDark: Bool, cancel: @escaping () -> Void, action: @escaping () -> Bool) -> ViewController
|
||||
|
||||
func makeStarsGiftController(context: AccountContext, birthdays: [EnginePeer.Id: TelegramBirthday]?, completion: @escaping (([EnginePeer.Id]) -> Void)) -> ViewController
|
||||
func makePremiumGiftController(context: AccountContext, source: PremiumGiftSource, completion: (([EnginePeer.Id]) -> Void)?) -> ViewController
|
||||
func makePremiumGiftController(context: AccountContext, source: PremiumGiftSource, completion: (([EnginePeer.Id]) -> Signal<Never, TransferStarGiftError>)?) -> ViewController
|
||||
func makeGiftOptionsController(context: AccountContext, peerId: EnginePeer.Id, premiumOptions: [CachedPremiumGiftOption], hasBirthday: Bool, completion: (() -> Void)?) -> ViewController
|
||||
func makePremiumPrivacyControllerController(context: AccountContext, subject: PremiumPrivacySubject, peerId: EnginePeer.Id) -> ViewController
|
||||
func makePremiumBoostLevelsController(context: AccountContext, peerId: EnginePeer.Id, subject: BoostSubject, boostStatus: ChannelBoostStatus, myBoostStatus: MyBoostStatus, forceDark: Bool, openStats: (() -> Void)?) -> ViewController
|
||||
|
@ -177,6 +177,7 @@ public enum BotPaymentFormRequestError {
|
||||
case generic
|
||||
case alreadyActive
|
||||
case noPaymentNeeded
|
||||
case disallowedStarGift
|
||||
}
|
||||
|
||||
extension BotPaymentInvoice {
|
||||
@ -473,6 +474,8 @@ func _internal_fetchBotPaymentForm(accountPeerId: PeerId, postbox: Postbox, netw
|
||||
|> `catch` { error -> Signal<Api.payments.PaymentForm, BotPaymentFormRequestError> in
|
||||
if error.errorDescription == "NO_PAYMENT_NEEDED" {
|
||||
return .fail(.noPaymentNeeded)
|
||||
} else if error.errorDescription == "USER_DISALLOWED_STARGIFTS" {
|
||||
return .fail(.disallowedStarGift)
|
||||
}
|
||||
return .fail(.generic)
|
||||
}
|
||||
@ -635,6 +638,7 @@ public enum SendBotPaymentFormError {
|
||||
case paymentFailed
|
||||
case alreadyPaid
|
||||
case starGiftOutOfStock
|
||||
case disallowedStarGift
|
||||
}
|
||||
|
||||
public enum SendBotPaymentResult {
|
||||
|
@ -766,7 +766,7 @@ func _internal_updateStarGiftsPinnedToTop(account: Account, peerId: EnginePeer.I
|
||||
|
||||
public enum TransferStarGiftError {
|
||||
case generic
|
||||
case disallowed
|
||||
case disallowedStarGift
|
||||
}
|
||||
|
||||
func _internal_transferStarGift(account: Account, prepaid: Bool, reference: StarGiftReference, peerId: EnginePeer.Id) -> Signal<Never, TransferStarGiftError> {
|
||||
@ -783,7 +783,10 @@ func _internal_transferStarGift(account: Account, prepaid: Bool, reference: Star
|
||||
}
|
||||
if prepaid {
|
||||
return account.network.request(Api.functions.payments.transferStarGift(stargift: starGift, toId: inputPeer))
|
||||
|> mapError { _ -> TransferStarGiftError in
|
||||
|> mapError { error -> TransferStarGiftError in
|
||||
if error.errorDescription == "USER_DISALLOWED_STARGIFTS" {
|
||||
return .disallowedStarGift
|
||||
}
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { updates -> Signal<Void, TransferStarGiftError> in
|
||||
@ -798,6 +801,8 @@ func _internal_transferStarGift(account: Account, prepaid: Bool, reference: Star
|
||||
|> `catch` { error -> Signal<BotPaymentForm?, TransferStarGiftError> in
|
||||
if case .noPaymentNeeded = error {
|
||||
return .single(nil)
|
||||
} else if case .disallowedStarGift = error {
|
||||
return .fail(.disallowedStarGift)
|
||||
}
|
||||
return .fail(.generic)
|
||||
}
|
||||
@ -1335,16 +1340,15 @@ private final class ProfileGiftsContextImpl {
|
||||
self.pushState()
|
||||
}
|
||||
|
||||
func transferStarGift(prepaid: Bool, reference: StarGiftReference, peerId: EnginePeer.Id) {
|
||||
self.actionDisposable.set(
|
||||
_internal_transferStarGift(account: self.account, prepaid: prepaid, reference: reference, peerId: peerId).startStrict()
|
||||
)
|
||||
func transferStarGift(prepaid: Bool, reference: StarGiftReference, peerId: EnginePeer.Id) -> Signal<Never, TransferStarGiftError> {
|
||||
if let count = self.count {
|
||||
self.count = max(0, count - 1)
|
||||
}
|
||||
self.gifts.removeAll(where: { $0.reference == reference })
|
||||
self.filteredGifts.removeAll(where: { $0.reference == reference })
|
||||
self.pushState()
|
||||
|
||||
return _internal_transferStarGift(account: self.account, prepaid: prepaid, reference: reference, peerId: peerId)
|
||||
}
|
||||
|
||||
func upgradeStarGift(formId: Int64?, reference: StarGiftReference, keepOriginalInfo: Bool) -> Signal<ProfileGiftsContext.State.StarGift, UpgradeStarGiftError> {
|
||||
@ -1703,9 +1707,17 @@ public final class ProfileGiftsContext {
|
||||
}
|
||||
}
|
||||
|
||||
public func transferStarGift(prepaid: Bool, reference: StarGiftReference, peerId: EnginePeer.Id) {
|
||||
self.impl.with { impl in
|
||||
impl.transferStarGift(prepaid: prepaid, reference: reference, peerId: peerId)
|
||||
public func transferStarGift(prepaid: Bool, reference: StarGiftReference, peerId: EnginePeer.Id) -> Signal<Never, TransferStarGiftError> {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
self.impl.with { impl in
|
||||
disposable.set(impl.transferStarGift(prepaid: prepaid, reference: reference, peerId: peerId).start(error: { error in
|
||||
subscriber.putError(error)
|
||||
}, completed: {
|
||||
subscriber.putCompletion()
|
||||
}))
|
||||
}
|
||||
return disposable
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -513,6 +513,9 @@ final class GiftOptionsScreenComponent: Component {
|
||||
}
|
||||
|
||||
let context = component.context
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
var dismissAlertImpl: (() -> Void)?
|
||||
let alertController = giftTransferAlertController(
|
||||
context: context,
|
||||
gift: transferGift,
|
||||
@ -521,65 +524,102 @@ final class GiftOptionsScreenComponent: Component {
|
||||
navigationController: mainController.navigationController as? NavigationController,
|
||||
commit: { [weak self, weak mainController] in
|
||||
let proceed: (Bool) -> Void = { waitForTopUp in
|
||||
var errorImpl: ((TransferStarGiftError) -> Void)?
|
||||
var completedImpl: (() -> Void)?
|
||||
|
||||
if waitForTopUp, let starsContext = context.starsContext {
|
||||
let _ = (starsContext.onUpdate
|
||||
|> deliverOnMainQueue).start(next: {
|
||||
let _ = (context.engine.payments.transferStarGift(prepaid: gift.transferStars == 0, reference: reference, peerId: peer.id)
|
||||
|> deliverOnMainQueue).start()
|
||||
|> deliverOnMainQueue).start(error: { error in
|
||||
errorImpl?(error)
|
||||
}, completed: {
|
||||
completedImpl?()
|
||||
})
|
||||
})
|
||||
} else {
|
||||
let _ = (context.engine.payments.transferStarGift(prepaid: gift.transferStars == 0, reference: reference, peerId: peer.id)
|
||||
|> deliverOnMainQueue).start()
|
||||
|> deliverOnMainQueue).start(error: { error in
|
||||
errorImpl?(error)
|
||||
}, completed: {
|
||||
completedImpl?()
|
||||
})
|
||||
}
|
||||
|
||||
guard let controller = mainController, let navigationController = controller.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
|
||||
if peer.id.namespace == Namespaces.Peer.CloudChannel {
|
||||
var controllers = navigationController.viewControllers
|
||||
controllers = controllers.filter { !($0 is GiftSetupScreen) && !($0 is GiftOptionsScreenProtocol) }
|
||||
var foundController = false
|
||||
for controller in controllers.reversed() {
|
||||
if let controller = controller as? PeerInfoScreen, controller.peerId == component.peerId {
|
||||
foundController = true
|
||||
break
|
||||
errorImpl = { [weak navigationController] error in
|
||||
guard let navigationController else {
|
||||
return
|
||||
}
|
||||
dismissAlertImpl?()
|
||||
|
||||
var errorText: String?
|
||||
switch error {
|
||||
case .disallowedStarGift:
|
||||
errorText = presentationData.strings.Gift_Send_ErrorDisallowed(peer.compactDisplayTitle).string
|
||||
default:
|
||||
errorText = presentationData.strings.Gift_Send_ErrorUnknown
|
||||
}
|
||||
|
||||
if let errorText = errorText {
|
||||
let alertController = textAlertController(context: context, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})], parseMarkdown: true)
|
||||
if let lastController = navigationController.viewControllers.last as? ViewController {
|
||||
lastController.present(alertController, in: .window(.root))
|
||||
}
|
||||
}
|
||||
if !foundController {
|
||||
if let controller = context.sharedContext.makePeerInfoController(
|
||||
context: context,
|
||||
updatedPresentationData: nil,
|
||||
peer: peer._asPeer(),
|
||||
mode: .gifts,
|
||||
avatarInitiallyExpanded: false,
|
||||
fromChat: false,
|
||||
requestsContext: nil
|
||||
) {
|
||||
controllers.append(controller)
|
||||
}
|
||||
}
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
} else {
|
||||
var controllers = navigationController.viewControllers
|
||||
controllers = controllers.filter { !($0 is GiftSetupScreen) && !($0 is GiftOptionsScreenProtocol) && !($0 is PeerInfoScreen) && !($0 is ContactSelectionController) }
|
||||
var foundController = false
|
||||
for controller in controllers.reversed() {
|
||||
if let chatController = controller as? ChatController, case .peer(id: component.peerId) = chatController.chatLocation {
|
||||
chatController.hintPlayNextOutgoingGift()
|
||||
foundController = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundController {
|
||||
let chatController = component.context.sharedContext.makeChatController(context: component.context, chatLocation: .peer(id: component.peerId), subject: nil, botStart: nil, mode: .standard(.default), params: nil)
|
||||
chatController.hintPlayNextOutgoingGift()
|
||||
controllers.append(chatController)
|
||||
}
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
if let completion = component.completion {
|
||||
completion()
|
||||
|
||||
completedImpl = {
|
||||
dismissAlertImpl?()
|
||||
|
||||
if peer.id.namespace == Namespaces.Peer.CloudChannel {
|
||||
var controllers = navigationController.viewControllers
|
||||
controllers = controllers.filter { !($0 is GiftSetupScreen) && !($0 is GiftOptionsScreenProtocol) }
|
||||
var foundController = false
|
||||
for controller in controllers.reversed() {
|
||||
if let controller = controller as? PeerInfoScreen, controller.peerId == component.peerId {
|
||||
foundController = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundController {
|
||||
if let controller = context.sharedContext.makePeerInfoController(
|
||||
context: context,
|
||||
updatedPresentationData: nil,
|
||||
peer: peer._asPeer(),
|
||||
mode: .gifts,
|
||||
avatarInitiallyExpanded: false,
|
||||
fromChat: false,
|
||||
requestsContext: nil
|
||||
) {
|
||||
controllers.append(controller)
|
||||
}
|
||||
}
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
} else {
|
||||
var controllers = navigationController.viewControllers
|
||||
controllers = controllers.filter { !($0 is GiftSetupScreen) && !($0 is GiftOptionsScreenProtocol) && !($0 is PeerInfoScreen) && !($0 is ContactSelectionController) }
|
||||
var foundController = false
|
||||
for controller in controllers.reversed() {
|
||||
if let chatController = controller as? ChatController, case .peer(id: component.peerId) = chatController.chatLocation {
|
||||
chatController.hintPlayNextOutgoingGift()
|
||||
foundController = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundController {
|
||||
let chatController = component.context.sharedContext.makeChatController(context: component.context, chatLocation: .peer(id: component.peerId), subject: nil, botStart: nil, mode: .standard(.default), params: nil)
|
||||
chatController.hintPlayNextOutgoingGift()
|
||||
controllers.append(chatController)
|
||||
}
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
if let completion = component.completion {
|
||||
completion()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -610,6 +650,10 @@ final class GiftOptionsScreenComponent: Component {
|
||||
}
|
||||
)
|
||||
controller.present(alertController, in: .window(.root))
|
||||
|
||||
dismissAlertImpl = { [weak alertController] in
|
||||
alertController?.dismissAnimated()
|
||||
}
|
||||
}
|
||||
|
||||
func update(component: GiftOptionsScreenComponent, availableSize: CGSize, state: State, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
|
||||
|
@ -465,12 +465,14 @@ final class GiftSetupScreenComponent: Component {
|
||||
switch error {
|
||||
case .starGiftOutOfStock:
|
||||
errorText = presentationData.strings.Gift_Send_ErrorOutOfStock
|
||||
case .disallowedStarGift:
|
||||
errorText = presentationData.strings.Gift_Send_ErrorDisallowed(self.peerMap[peerId]?.compactDisplayTitle ?? "").string
|
||||
default:
|
||||
errorText = presentationData.strings.Gift_Send_ErrorUnknown
|
||||
}
|
||||
|
||||
if let errorText = errorText {
|
||||
let alertController = textAlertController(context: component.context, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
|
||||
let alertController = textAlertController(context: component.context, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})], parseMarkdown: true)
|
||||
controller.present(alertController, in: .window(.root))
|
||||
}
|
||||
})
|
||||
|
@ -50,6 +50,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/PremiumLockButtonSubtitleComponent",
|
||||
"//submodules/TelegramUI/Components/Stars/StarsBalanceOverlayComponent",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessagePaymentAlertController",
|
||||
"//submodules/ActivityIndicator",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -13,6 +13,7 @@ import AvatarNode
|
||||
import Markdown
|
||||
import GiftItemComponent
|
||||
import ChatMessagePaymentAlertController
|
||||
import ActivityIndicator
|
||||
|
||||
private final class GiftTransferAlertContentNode: AlertContentNode {
|
||||
private let context: AccountContext
|
||||
@ -31,9 +32,19 @@ private final class GiftTransferAlertContentNode: AlertContentNode {
|
||||
private let actionNodesSeparator: ASDisplayNode
|
||||
private let actionNodes: [TextAlertContentActionNode]
|
||||
private let actionVerticalSeparators: [ASDisplayNode]
|
||||
|
||||
private var activityIndicator: ActivityIndicator?
|
||||
|
||||
private var validLayout: CGSize?
|
||||
|
||||
var inProgress = false {
|
||||
didSet {
|
||||
if let size = self.validLayout {
|
||||
let _ = self.updateLayout(size: size, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override var dismissOnOutsideTap: Bool {
|
||||
return self.isUserInteractionEnabled
|
||||
}
|
||||
@ -248,6 +259,23 @@ private final class GiftTransferAlertContentNode: AlertContentNode {
|
||||
nodeIndex += 1
|
||||
}
|
||||
|
||||
if self.inProgress {
|
||||
let activityIndicator: ActivityIndicator
|
||||
if let current = self.activityIndicator {
|
||||
activityIndicator = current
|
||||
} else {
|
||||
activityIndicator = ActivityIndicator(type: .custom(self.presentationTheme.list.freeInputField.controlColor, 18.0, 1.5, false))
|
||||
self.addSubnode(activityIndicator)
|
||||
}
|
||||
|
||||
if let actionNode = self.actionNodes.first {
|
||||
actionNode.isHidden = true
|
||||
|
||||
let indicatorSize = CGSize(width: 22.0, height: 22.0)
|
||||
transition.updateFrame(node: activityIndicator, frame: CGRect(origin: CGPoint(x: actionNode.frame.minX + floor((actionNode.frame.width - indicatorSize.width) / 2.0), y: actionNode.frame.minY + floor((actionNode.frame.height - indicatorSize.height) / 2.0)), size: indicatorSize))
|
||||
}
|
||||
}
|
||||
|
||||
return resultSize
|
||||
}
|
||||
}
|
||||
@ -274,17 +302,18 @@ public func giftTransferAlertController(
|
||||
buttonText = strings.Gift_Transfer_Confirmation_TransferFree
|
||||
}
|
||||
|
||||
var contentNode: GiftTransferAlertContentNode?
|
||||
var dismissImpl: ((Bool) -> Void)?
|
||||
let actions: [TextAlertAction] = [TextAlertAction(type: .defaultAction, title: buttonText, action: {
|
||||
dismissImpl?(true)
|
||||
let actions: [TextAlertAction] = [TextAlertAction(type: .defaultAction, title: buttonText, action: { [weak contentNode] in
|
||||
contentNode?.inProgress = true
|
||||
commit()
|
||||
}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
|
||||
dismissImpl?(true)
|
||||
})]
|
||||
|
||||
let contentNode = GiftTransferAlertContentNode(context: context, theme: AlertControllerTheme(presentationData: presentationData), ptheme: presentationData.theme, strings: strings, gift: gift, peer: peer, title: title, text: text, actions: actions)
|
||||
contentNode = GiftTransferAlertContentNode(context: context, theme: AlertControllerTheme(presentationData: presentationData), ptheme: presentationData.theme, strings: strings, gift: gift, peer: peer, title: title, text: text, actions: actions)
|
||||
|
||||
let controller = ChatMessagePaymentAlertController(context: context, presentationData: presentationData, contentNode: contentNode, navigationController: navigationController, showBalance: transferStars > 0)
|
||||
let controller = ChatMessagePaymentAlertController(context: context, presentationData: presentationData, contentNode: contentNode!, navigationController: navigationController, showBalance: transferStars > 0)
|
||||
dismissImpl = { [weak controller] animated in
|
||||
if animated {
|
||||
controller?.dismissAnimated()
|
||||
|
@ -2415,7 +2415,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
case upgradePreview([StarGift.UniqueGift.Attribute], String)
|
||||
case wearPreview(StarGift.UniqueGift)
|
||||
|
||||
var arguments: (peerId: EnginePeer.Id?, fromPeerId: EnginePeer.Id?, fromPeerName: String?, messageId: EngineMessage.Id?, reference: StarGiftReference?, incoming: Bool, gift: StarGift, date: Int32, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, converted: Bool, upgraded: Bool, canUpgrade: Bool, upgradeStars: Int64?, transferStars: Int64?, canExportDate: Int32?, upgradeMessageId: Int32?)? {
|
||||
var arguments: (peerId: EnginePeer.Id?, fromPeerId: EnginePeer.Id?, fromPeerName: String?, messageId: EngineMessage.Id?, reference: StarGiftReference?, incoming: Bool, gift: StarGift, date: Int32, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, pinnedToTop: Bool?, converted: Bool, upgraded: Bool, canUpgrade: Bool, upgradeStars: Int64?, transferStars: Int64?, canExportDate: Int32?, upgradeMessageId: Int32?)? {
|
||||
switch self {
|
||||
case let .message(message):
|
||||
if let action = message.media.first(where: { $0 is TelegramMediaAction }) as? TelegramMediaAction {
|
||||
@ -2427,7 +2427,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
} else {
|
||||
reference = .message(messageId: message.id)
|
||||
}
|
||||
return (message.id.peerId, senderId ?? message.author?.id, message.author?.compactDisplayTitle, message.id, reference, message.flags.contains(.Incoming), gift, message.timestamp, convertStars, text, entities, nameHidden, savedToProfile, converted, upgraded, canUpgrade, upgradeStars, nil, nil, upgradeMessageId)
|
||||
return (message.id.peerId, senderId ?? message.author?.id, message.author?.compactDisplayTitle, message.id, reference, message.flags.contains(.Incoming), gift, message.timestamp, convertStars, text, entities, nameHidden, savedToProfile, nil, converted, upgraded, canUpgrade, upgradeStars, nil, nil, upgradeMessageId)
|
||||
case let .starGiftUnique(gift, isUpgrade, isTransferred, savedToProfile, canExportDate, transferStars, _, peerId, senderId, savedId):
|
||||
var reference: StarGiftReference
|
||||
if let peerId, let savedId {
|
||||
@ -2447,19 +2447,19 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
} else {
|
||||
incoming = message.flags.contains(.Incoming)
|
||||
}
|
||||
return (message.id.peerId, senderId ?? message.author?.id, message.author?.compactDisplayTitle, message.id, reference, incoming, gift, message.timestamp, nil, nil, nil, false, savedToProfile, false, false, false, nil, transferStars, canExportDate, nil)
|
||||
return (message.id.peerId, senderId ?? message.author?.id, message.author?.compactDisplayTitle, message.id, reference, incoming, gift, message.timestamp, nil, nil, nil, false, savedToProfile, nil, false, false, false, nil, transferStars, canExportDate, nil)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
case let .uniqueGift(gift), let .wearPreview(gift):
|
||||
return (nil, nil, nil, nil, nil, false, .unique(gift), 0, nil, nil, nil, false, false, false, false, false, nil, nil, nil, nil)
|
||||
return (nil, nil, nil, nil, nil, false, .unique(gift), 0, nil, nil, nil, false, false, nil, false, false, false, nil, nil, nil, nil)
|
||||
case let .profileGift(peerId, gift):
|
||||
var messageId: EngineMessage.Id?
|
||||
if case let .message(messageIdValue) = gift.reference {
|
||||
messageId = messageIdValue
|
||||
}
|
||||
return (peerId, gift.fromPeer?.id, gift.fromPeer?.compactDisplayTitle, messageId, gift.reference, false, gift.gift, gift.date, gift.convertStars, gift.text, gift.entities, gift.nameHidden, gift.savedToProfile, false, false, gift.canUpgrade, gift.upgradeStars, gift.transferStars, gift.canExportDate, nil)
|
||||
return (peerId, gift.fromPeer?.id, gift.fromPeer?.compactDisplayTitle, messageId, gift.reference, false, gift.gift, gift.date, gift.convertStars, gift.text, gift.entities, gift.nameHidden, gift.savedToProfile, gift.pinnedToTop, false, false, gift.canUpgrade, gift.upgradeStars, gift.transferStars, gift.canExportDate, nil)
|
||||
case .soldOutGift:
|
||||
return nil
|
||||
case .upgradePreview:
|
||||
@ -2488,8 +2488,9 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
forceDark: Bool = false,
|
||||
updateSavedToProfile: ((StarGiftReference, Bool) -> Void)? = nil,
|
||||
convertToStars: (() -> Void)? = nil,
|
||||
transferGift: ((Bool, EnginePeer.Id) -> Void)? = nil,
|
||||
transferGift: ((Bool, EnginePeer.Id) -> Signal<Never, TransferStarGiftError>)? = nil,
|
||||
upgradeGift: ((Int64?, Bool) -> Signal<ProfileGiftsContext.State.StarGift, UpgradeStarGiftError>)? = nil,
|
||||
togglePinnedToTop: ((Bool) -> Bool)? = nil,
|
||||
shareStory: ((StarGift.UniqueGift) -> Void)? = nil
|
||||
) {
|
||||
self.context = context
|
||||
@ -2822,19 +2823,19 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
}
|
||||
let controller = context.sharedContext.makePremiumGiftController(context: context, source: .starGiftTransfer(birthdays, reference, gift, transferStars, arguments.canExportDate, showSelf), completion: { peerIds in
|
||||
guard let peerId = peerIds.first else {
|
||||
return
|
||||
return .complete()
|
||||
}
|
||||
if let transferGift {
|
||||
transferGift(transferStars == 0, peerId)
|
||||
} else {
|
||||
let _ = (context.engine.payments.transferStarGift(prepaid: transferStars == 0, reference: reference, peerId: peerId)
|
||||
|> deliverOnMainQueue).start()
|
||||
}
|
||||
Queue.mainQueue().after(1.0, {
|
||||
Queue.mainQueue().after(1.5, {
|
||||
if transferStars > 0 {
|
||||
context.starsContext?.load(force: true)
|
||||
}
|
||||
})
|
||||
if let transferGift {
|
||||
return transferGift(transferStars == 0, peerId)
|
||||
} else {
|
||||
return (context.engine.payments.transferStarGift(prepaid: transferStars == 0, reference: reference, peerId: peerId)
|
||||
|> deliverOnMainQueue)
|
||||
}
|
||||
})
|
||||
navigationController.pushViewController(controller)
|
||||
})
|
||||
@ -2979,6 +2980,37 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
return
|
||||
}
|
||||
var items: [ContextMenuItem] = []
|
||||
let strings = presentationData.strings
|
||||
|
||||
if let _ = arguments.reference, case .unique = arguments.gift, let togglePinnedToTop, let pinnedToTop = arguments.pinnedToTop {
|
||||
items.append(.action(ContextMenuActionItem(text: pinnedToTop ? strings.PeerInfo_Gifts_Context_Unpin : strings.PeerInfo_Gifts_Context_Pin , icon: { theme in generateTintedImage(image: UIImage(bundleImageName: pinnedToTop ? "Chat/Context Menu/Unpin" : "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
|
||||
c?.dismiss(completion: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
let pinnedToTop = !pinnedToTop
|
||||
if togglePinnedToTop(pinnedToTop) {
|
||||
if pinnedToTop {
|
||||
self.dismissAnimated()
|
||||
} else {
|
||||
let toastText = strings.PeerInfo_Gifts_ToastUnpinned_Text
|
||||
self.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_toastunpin", scale: 0.06, colors: [:], title: nil, text: toastText, customUndoText: nil, timeout: 5), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
||||
if case let .profileGift(peerId, gift) = self.subject {
|
||||
self.subject = .profileGift(peerId, gift.withPinnedToTop(false))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var maxPinnedCount: Int = 6
|
||||
if let value = context.currentAppConfiguration.with({ $0 }).data?["stargifts_pinned_to_top_limit"] as? Double {
|
||||
maxPinnedCount = Int(value)
|
||||
}
|
||||
self.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: strings.PeerInfo_Gifts_ToastPinLimit_Text(Int32(maxPinnedCount)), timeout: nil, customUndoText: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
||||
}
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_CopyLink, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
|
@ -4855,9 +4855,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
},
|
||||
transferGift: { [weak profileGifts] prepaid, peerId in
|
||||
guard let profileGifts, let reference = gift.reference else {
|
||||
return
|
||||
return .complete()
|
||||
}
|
||||
profileGifts.transferStarGift(prepaid: prepaid, reference: reference, peerId: peerId)
|
||||
return profileGifts.transferStarGift(prepaid: prepaid, reference: reference, peerId: peerId)
|
||||
},
|
||||
upgradeGift: { [weak profileGifts] formId, keepOriginalInfo in
|
||||
guard let profileGifts, let reference = gift.reference else {
|
||||
|
@ -518,9 +518,9 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
},
|
||||
transferGift: { [weak self] prepaid, peerId in
|
||||
guard let self, let reference = product.reference else {
|
||||
return
|
||||
return .complete()
|
||||
}
|
||||
self.profileGifts.transferStarGift(prepaid: prepaid, reference: reference, peerId: peerId)
|
||||
return self.profileGifts.transferStarGift(prepaid: prepaid, reference: reference, peerId: peerId)
|
||||
},
|
||||
upgradeGift: { [weak self] formId, keepOriginalInfo in
|
||||
guard let self, let reference = product.reference else {
|
||||
@ -528,6 +528,27 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
}
|
||||
return self.profileGifts.upgradeStarGift(formId: formId, reference: reference, keepOriginalInfo: keepOriginalInfo)
|
||||
},
|
||||
togglePinnedToTop: { [weak self] pinnedToTop in
|
||||
guard let self else {
|
||||
return false
|
||||
}
|
||||
if pinnedToTop && self.pinnedReferences.count >= self.maxPinnedCount {
|
||||
return false
|
||||
}
|
||||
if let reference = product.reference {
|
||||
self.profileGifts.updateStarGiftPinnedToTop(reference: reference, pinnedToTop: pinnedToTop)
|
||||
|
||||
if pinnedToTop {
|
||||
let _ = self.scrollToTop()
|
||||
Queue.mainQueue().after(0.35) {
|
||||
let toastTitle = params.presentationData.strings.PeerInfo_Gifts_ToastPinned_Title
|
||||
let toastText = params.presentationData.strings.PeerInfo_Gifts_ToastPinned_Text
|
||||
self.parentController?.present(UndoOverlayController(presentationData: params.presentationData, content: .universal(animation: "anim_toastpin", scale: 0.06, colors: [:], title: toastTitle, text: toastText, customUndoText: nil, timeout: 5), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
},
|
||||
shareStory: { [weak self] uniqueGift in
|
||||
guard let self, let parentController = self.parentController else {
|
||||
return
|
||||
@ -977,7 +998,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
let pinnedToTop = !gift.pinnedToTop
|
||||
|
||||
if pinnedToTop && self.pinnedReferences.count >= self.maxPinnedCount {
|
||||
self.parentController?.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.PeerInfo_Gifts_ToastPinLimit_Text(Int32(self.maxPinnedCount)), timeout: nil, customUndoText: nil), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
self.parentController?.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: strings.PeerInfo_Gifts_ToastPinLimit_Text(Int32(self.maxPinnedCount)), timeout: nil, customUndoText: nil), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
return
|
||||
}
|
||||
|
||||
@ -989,10 +1010,10 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
let toastText: String
|
||||
if !pinnedToTop {
|
||||
toastTitle = nil
|
||||
toastText = presentationData.strings.PeerInfo_Gifts_ToastUnpinned_Text
|
||||
toastText = strings.PeerInfo_Gifts_ToastUnpinned_Text
|
||||
} else {
|
||||
toastTitle = presentationData.strings.PeerInfo_Gifts_ToastPinned_Title
|
||||
toastText = presentationData.strings.PeerInfo_Gifts_ToastPinned_Text
|
||||
toastTitle = strings.PeerInfo_Gifts_ToastPinned_Title
|
||||
toastText = strings.PeerInfo_Gifts_ToastPinned_Text
|
||||
}
|
||||
self.parentController?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: !pinnedToTop ? "anim_toastunpin" : "anim_toastpin", scale: 0.06, colors: [:], title: toastTitle, text: toastText, customUndoText: nil, timeout: 5), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
})
|
||||
@ -1200,14 +1221,14 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
let transferStars = gift.transferStars ?? 0
|
||||
let controller = context.sharedContext.makePremiumGiftController(context: context, source: .starGiftTransfer(birthdays, reference, uniqueGift, transferStars, gift.canExportDate, showSelf), completion: { [weak self] peerIds in
|
||||
guard let self, let peerId = peerIds.first else {
|
||||
return
|
||||
return .complete()
|
||||
}
|
||||
self.profileGifts.transferStarGift(prepaid: transferStars == 0, reference: reference, peerId: peerId)
|
||||
Queue.mainQueue().after(1.0, {
|
||||
Queue.mainQueue().after(1.5, {
|
||||
if transferStars > 0 {
|
||||
context.starsContext?.load(force: true)
|
||||
}
|
||||
})
|
||||
return self.profileGifts.transferStarGift(prepaid: transferStars == 0, reference: reference, peerId: peerId)
|
||||
})
|
||||
self.parentController?.push(controller)
|
||||
})
|
||||
|
@ -2674,7 +2674,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
return controller
|
||||
}
|
||||
|
||||
public func makePremiumGiftController(context: AccountContext, source: PremiumGiftSource, completion: (([EnginePeer.Id]) -> Void)?) -> ViewController {
|
||||
public func makePremiumGiftController(context: AccountContext, source: PremiumGiftSource, completion: (([EnginePeer.Id]) -> Signal<Never, TransferStarGiftError>)?) -> ViewController {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
var presentExportAlertImpl: (() -> Void)?
|
||||
@ -2912,6 +2912,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
guard let controller, case let .starGiftTransfer(_, _, gift, transferStars, _, _) = source else {
|
||||
return
|
||||
}
|
||||
var dismissAlertImpl: (() -> Void)?
|
||||
let alertController = giftTransferAlertController(
|
||||
context: context,
|
||||
gift: gift,
|
||||
@ -2920,61 +2921,89 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
navigationController: controller.navigationController as? NavigationController,
|
||||
commit: { [weak controller] in
|
||||
let proceed: (Bool) -> Void = { waitForTopUp in
|
||||
completion?([peer.id])
|
||||
|
||||
guard let controller, let navigationController = controller.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
var controllers = navigationController.viewControllers
|
||||
controllers = controllers.filter { !($0 is ContactSelectionController) }
|
||||
|
||||
if !isChannelGift {
|
||||
if peer.id.namespace == Namespaces.Peer.CloudChannel {
|
||||
if let controller = context.sharedContext.makePeerInfoController(
|
||||
context: context,
|
||||
updatedPresentationData: nil,
|
||||
peer: peer._asPeer(),
|
||||
mode: .gifts,
|
||||
avatarInitiallyExpanded: false,
|
||||
fromChat: false,
|
||||
requestsContext: nil
|
||||
) {
|
||||
controllers.append(controller)
|
||||
if let completion {
|
||||
let _ = (completion([peer.id])
|
||||
|> deliverOnMainQueue).startStandalone(error: { [weak navigationController] error in
|
||||
guard let navigationController else {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
var foundController = false
|
||||
for controller in controllers.reversed() {
|
||||
if let chatController = controller as? ChatController, case .peer(id: peer.id) = chatController.chatLocation {
|
||||
chatController.hintPlayNextOutgoingGift()
|
||||
foundController = true
|
||||
break
|
||||
dismissAlertImpl?()
|
||||
|
||||
var errorText: String?
|
||||
switch error {
|
||||
case .disallowedStarGift:
|
||||
errorText = presentationData.strings.Gift_Send_ErrorDisallowed(peer.compactDisplayTitle).string
|
||||
default:
|
||||
errorText = presentationData.strings.Gift_Send_ErrorUnknown
|
||||
}
|
||||
|
||||
if let errorText = errorText {
|
||||
let alertController = textAlertController(context: context, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})], parseMarkdown: true)
|
||||
if let lastController = navigationController.viewControllers.last as? ViewController {
|
||||
lastController.present(alertController, in: .window(.root))
|
||||
}
|
||||
}
|
||||
if !foundController {
|
||||
let chatController = context.sharedContext.makeChatController(context: context, chatLocation: .peer(id: peer.id), subject: nil, botStart: nil, mode: .standard(.default), params: nil)
|
||||
chatController.hintPlayNextOutgoingGift()
|
||||
controllers.append(chatController)
|
||||
}, completed: { [weak navigationController] in
|
||||
guard let navigationController else {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
|
||||
Queue.mainQueue().after(0.3) {
|
||||
let tooltipController = UndoOverlayController(
|
||||
presentationData: presentationData,
|
||||
content: .forward(savedMessages: false, text: presentationData.strings.Gift_Transfer_Success("\(gift.title) #\(presentationStringsFormattedNumber(gift.number, presentationData.dateTimeFormat.groupingSeparator))", peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string),
|
||||
elevatedLayout: false,
|
||||
action: { _ in return true }
|
||||
)
|
||||
if let lastController = controllers.last as? ViewController {
|
||||
lastController.present(tooltipController, in: .window(.root))
|
||||
}
|
||||
|
||||
Queue.mainQueue().after(0.5) {
|
||||
dismissAlertImpl?()
|
||||
|
||||
var controllers = navigationController.viewControllers
|
||||
controllers = controllers.filter { !($0 is GiftViewScreen) }
|
||||
navigationController.setViewControllers(controllers, animated: false)
|
||||
}
|
||||
controllers = controllers.filter { !($0 is ContactSelectionController) }
|
||||
if !isChannelGift {
|
||||
if peer.id.namespace == Namespaces.Peer.CloudChannel {
|
||||
if let controller = context.sharedContext.makePeerInfoController(
|
||||
context: context,
|
||||
updatedPresentationData: nil,
|
||||
peer: peer._asPeer(),
|
||||
mode: .gifts,
|
||||
avatarInitiallyExpanded: false,
|
||||
fromChat: false,
|
||||
requestsContext: nil
|
||||
) {
|
||||
controllers.append(controller)
|
||||
}
|
||||
} else {
|
||||
var foundController = false
|
||||
for controller in controllers.reversed() {
|
||||
if let chatController = controller as? ChatController, case .peer(id: peer.id) = chatController.chatLocation {
|
||||
chatController.hintPlayNextOutgoingGift()
|
||||
foundController = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundController {
|
||||
let chatController = context.sharedContext.makeChatController(context: context, chatLocation: .peer(id: peer.id), subject: nil, botStart: nil, mode: .standard(.default), params: nil)
|
||||
chatController.hintPlayNextOutgoingGift()
|
||||
controllers.append(chatController)
|
||||
}
|
||||
}
|
||||
}
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
|
||||
Queue.mainQueue().after(0.3) {
|
||||
let tooltipController = UndoOverlayController(
|
||||
presentationData: presentationData,
|
||||
content: .forward(savedMessages: false, text: presentationData.strings.Gift_Transfer_Success("\(gift.title) #\(presentationStringsFormattedNumber(gift.number, presentationData.dateTimeFormat.groupingSeparator))", peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string),
|
||||
elevatedLayout: false,
|
||||
action: { _ in return true }
|
||||
)
|
||||
if let lastController = navigationController.viewControllers.last as? ViewController {
|
||||
lastController.present(tooltipController, in: .window(.root))
|
||||
}
|
||||
|
||||
Queue.mainQueue().after(0.5) {
|
||||
var controllers = navigationController.viewControllers
|
||||
controllers = controllers.filter { !($0 is GiftViewScreen) }
|
||||
navigationController.setViewControllers(controllers, animated: false)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -3005,6 +3034,10 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
}
|
||||
)
|
||||
controller.present(alertController, in: .window(.root))
|
||||
|
||||
dismissAlertImpl = { [weak alertController] in
|
||||
alertController?.dismissAnimated()
|
||||
}
|
||||
}
|
||||
|
||||
return controller
|
||||
|
Loading…
x
Reference in New Issue
Block a user