mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
a1b70a7070
@ -568,6 +568,7 @@ public enum PeerInfoControllerMode {
|
|||||||
case forumTopic(thread: ChatReplyThreadMessage)
|
case forumTopic(thread: ChatReplyThreadMessage)
|
||||||
case recommendedChannels
|
case recommendedChannels
|
||||||
case myProfile
|
case myProfile
|
||||||
|
case myProfileGifts
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ContactListActionItemInlineIconPosition {
|
public enum ContactListActionItemInlineIconPosition {
|
||||||
@ -975,6 +976,8 @@ public protocol SharedAccountContext: AnyObject {
|
|||||||
func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource, forceDark: Bool, dismissed: (() -> Void)?) -> ViewController
|
func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource, forceDark: Bool, dismissed: (() -> Void)?) -> ViewController
|
||||||
func makePremiumDemoController(context: AccountContext, subject: PremiumDemoSubject, forceDark: Bool, action: @escaping () -> Void, dismissed: (() -> Void)?) -> ViewController
|
func makePremiumDemoController(context: AccountContext, subject: PremiumDemoSubject, forceDark: Bool, action: @escaping () -> Void, dismissed: (() -> Void)?) -> ViewController
|
||||||
func makePremiumLimitController(context: AccountContext, subject: PremiumLimitSubject, count: Int32, forceDark: Bool, cancel: @escaping () -> Void, action: @escaping () -> Bool) -> ViewController
|
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]) -> Void)?) -> ViewController
|
||||||
func makePremiumPrivacyControllerController(context: AccountContext, subject: PremiumPrivacySubject, peerId: EnginePeer.Id) -> 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
|
func makePremiumBoostLevelsController(context: AccountContext, peerId: EnginePeer.Id, subject: BoostSubject, boostStatus: ChannelBoostStatus, myBoostStatus: MyBoostStatus, forceDark: Bool, openStats: (() -> Void)?) -> ViewController
|
||||||
|
@ -191,7 +191,7 @@ func _internal_keepCachedStarGiftsUpdated(postbox: Postbox, network: Network) ->
|
|||||||
|
|
||||||
func managedStarGiftsUpdates(postbox: Postbox, network: Network) -> Signal<Never, NoError> {
|
func managedStarGiftsUpdates(postbox: Postbox, network: Network) -> Signal<Never, NoError> {
|
||||||
let poll = _internal_keepCachedStarGiftsUpdated(postbox: postbox, network: network)
|
let poll = _internal_keepCachedStarGiftsUpdated(postbox: postbox, network: network)
|
||||||
return (poll |> then(.complete() |> suspendAwareDelay(2.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart
|
return (poll |> then(.complete() |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart
|
||||||
}
|
}
|
||||||
|
|
||||||
func _internal_convertStarGift(account: Account, messageId: EngineMessage.Id) -> Signal<Never, NoError> {
|
func _internal_convertStarGift(account: Account, messageId: EngineMessage.Id) -> Signal<Never, NoError> {
|
||||||
|
@ -228,7 +228,8 @@ private final class SheetPageContent: CombinedComponent {
|
|||||||
component.context.sharedContext.openExternalUrl(context: component.context, urlContext: .generic, url: strings.ReportAd_Help_URL, forceExternal: true, presentationData: presentationData, navigationController: nil, dismissInput: {})
|
component.context.sharedContext.openExternalUrl(context: component.context, urlContext: .generic, url: strings.ReportAd_Help_URL, forceExternal: true, presentationData: presentationData, navigationController: nil, dismissInput: {})
|
||||||
}
|
}
|
||||||
)),
|
)),
|
||||||
items: items
|
items: items,
|
||||||
|
isModal: true
|
||||||
),
|
),
|
||||||
environment: {},
|
environment: {},
|
||||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: .greatestFiniteMagnitude),
|
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: .greatestFiniteMagnitude),
|
||||||
|
@ -332,6 +332,9 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
case let .starGift(gift, convertStars, giftText, entities, nameHidden, savedToProfile, converted):
|
case let .starGift(gift, convertStars, giftText, entities, nameHidden, savedToProfile, converted):
|
||||||
let _ = nameHidden
|
let _ = nameHidden
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
|
if !incoming {
|
||||||
|
buttonTitle = ""
|
||||||
|
}
|
||||||
let authorName = item.message.author.flatMap { EnginePeer($0) }?.compactDisplayTitle ?? ""
|
let authorName = item.message.author.flatMap { EnginePeer($0) }?.compactDisplayTitle ?? ""
|
||||||
title = "Gift from \(authorName)"
|
title = "Gift from \(authorName)"
|
||||||
if let giftText, !giftText.isEmpty {
|
if let giftText, !giftText.isEmpty {
|
||||||
@ -397,8 +400,11 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
let (buttonTitleLayout, buttonTitleApply) = makeButtonTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: buttonTitle, font: Font.semibold(15.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
let (buttonTitleLayout, buttonTitleApply) = makeButtonTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: buttonTitle, font: Font.semibold(15.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
let (ribbonTextLayout, ribbonTextApply) = makeRibbonTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: ribbonTitle, font: Font.semibold(11.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
let (ribbonTextLayout, ribbonTextApply) = makeRibbonTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: ribbonTitle, font: Font.semibold(11.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
giftSize.height = titleLayout.size.height + textSpacing + subtitleLayout.size.height + 212.0
|
giftSize.height = titleLayout.size.height + textSpacing + subtitleLayout.size.height + 164.0
|
||||||
|
if !buttonTitle.isEmpty {
|
||||||
|
giftSize.height += 48.0
|
||||||
|
}
|
||||||
|
|
||||||
var labelRects = labelLayout.linesRects()
|
var labelRects = labelLayout.linesRects()
|
||||||
if labelRects.count > 1 {
|
if labelRects.count > 1 {
|
||||||
@ -458,6 +464,9 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
let animationFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - iconSize.width) / 2.0), y: mediaBackgroundFrame.minY - 16.0 + iconOffset), size: iconSize)
|
let animationFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - iconSize.width) / 2.0), y: mediaBackgroundFrame.minY - 16.0 + iconOffset), size: iconSize)
|
||||||
strongSelf.animationNode.frame = animationFrame
|
strongSelf.animationNode.frame = animationFrame
|
||||||
|
|
||||||
|
strongSelf.buttonNode.isHidden = buttonTitle.isEmpty
|
||||||
|
strongSelf.buttonTitleNode.isHidden = buttonTitle.isEmpty
|
||||||
|
|
||||||
if strongSelf.item == nil {
|
if strongSelf.item == nil {
|
||||||
strongSelf.animationNode.started = { [weak self] in
|
strongSelf.animationNode.started = { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
@ -162,7 +162,7 @@ private final class SheetPageContent: CombinedComponent {
|
|||||||
transition: .immediate
|
transition: .immediate
|
||||||
)
|
)
|
||||||
context.add(back
|
context.add(back
|
||||||
.position(CGPoint(x: sideInset + back.size.width / 2.0 - (component.title != nil ? 8.0 : 0.0), y: contentSize.height + back.size.height / 2.0))
|
.position(CGPoint(x: sideInset + back.size.width / 2.0 - (!component.isFirst ? 8.0 : 0.0), y: contentSize.height + back.size.height / 2.0))
|
||||||
)
|
)
|
||||||
|
|
||||||
let constrainedTitleWidth = context.availableSize.width - (back.size.width + 16.0) * 2.0
|
let constrainedTitleWidth = context.availableSize.width - (back.size.width + 16.0) * 2.0
|
||||||
@ -280,7 +280,8 @@ private final class SheetPageContent: CombinedComponent {
|
|||||||
maximumNumberOfLines: 0
|
maximumNumberOfLines: 0
|
||||||
)),
|
)),
|
||||||
footer: footer,
|
footer: footer,
|
||||||
items: items
|
items: items,
|
||||||
|
isModal: true
|
||||||
),
|
),
|
||||||
environment: {},
|
environment: {},
|
||||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: .greatestFiniteMagnitude),
|
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: .greatestFiniteMagnitude),
|
||||||
@ -696,12 +697,10 @@ public final class ContentReportScreen: ViewControllerComponentContainer {
|
|||||||
|
|
||||||
switch result {
|
switch result {
|
||||||
case .reported:
|
case .reported:
|
||||||
Queue.mainQueue().after(0.1) {
|
|
||||||
completed()
|
|
||||||
}
|
|
||||||
|
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
Queue.mainQueue().after(0.4, {
|
Queue.mainQueue().after(0.4, {
|
||||||
|
completed()
|
||||||
|
|
||||||
(navigationController?.viewControllers.last as? ViewController)?.present(UndoOverlayController(presentationData: presentationData, content: .emoji(name: "PoliceCar", text: presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return true }), in: .current)
|
(navigationController?.viewControllers.last as? ViewController)?.present(UndoOverlayController(presentationData: presentationData, content: .emoji(name: "PoliceCar", text: presentationData.strings.Report_Succeed), elevatedLayout: false, action: { _ in return true }), in: .current)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,10 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
if let arguments = subject.arguments {
|
if let arguments = subject.arguments {
|
||||||
let peerIds: [EnginePeer.Id] = [arguments.peerId, context.account.peerId]
|
var peerIds: [EnginePeer.Id] = [arguments.peerId, context.account.peerId]
|
||||||
|
if let fromPeerId = arguments.fromPeerId {
|
||||||
|
peerIds.append(fromPeerId)
|
||||||
|
}
|
||||||
self.disposable = (context.engine.data.get(
|
self.disposable = (context.engine.data.get(
|
||||||
EngineDataMap(
|
EngineDataMap(
|
||||||
peerIds.map { peerId -> TelegramEngine.EngineData.Item.Peer.Peer in
|
peerIds.map { peerId -> TelegramEngine.EngineData.Item.Peer.Peer in
|
||||||
@ -204,7 +207,11 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||||||
descriptionText = "You converted this gift to \(convertStars) Stars. [More About Stars >]()"
|
descriptionText = "You converted this gift to \(convertStars) Stars. [More About Stars >]()"
|
||||||
}
|
}
|
||||||
} else if let peerId = component.subject.arguments?.peerId, let peer = state.peerMap[peerId] {
|
} else if let peerId = component.subject.arguments?.peerId, let peer = state.peerMap[peerId] {
|
||||||
descriptionText = "\(peer.compactDisplayTitle) can keep this gift in their Profile or convert it to \(convertStars) Stars. [More About Stars >]()"
|
if case .message = component.subject {
|
||||||
|
descriptionText = "\(peer.compactDisplayTitle) can keep this gift in their Profile or convert it to \(convertStars) Stars. [More About Stars >]()"
|
||||||
|
} else {
|
||||||
|
descriptionText = ""
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
descriptionText = ""
|
descriptionText = ""
|
||||||
}
|
}
|
||||||
@ -273,10 +280,10 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||||||
let tableLinkColor = theme.list.itemAccentColor
|
let tableLinkColor = theme.list.itemAccentColor
|
||||||
var tableItems: [TableComponent.Item] = []
|
var tableItems: [TableComponent.Item] = []
|
||||||
|
|
||||||
if let peerId = component.subject.arguments?.peerId, let peer = state.peerMap[peerId] {
|
if let peerId = component.subject.arguments?.fromPeerId, let peer = state.peerMap[peerId] {
|
||||||
tableItems.append(.init(
|
tableItems.append(.init(
|
||||||
id: "to",
|
id: "from",
|
||||||
title: incoming ? strings.Stars_Transaction_From : strings.Stars_Transaction_To,
|
title: strings.Stars_Transaction_From,
|
||||||
component: AnyComponent(
|
component: AnyComponent(
|
||||||
Button(
|
Button(
|
||||||
content: AnyComponent(
|
content: AnyComponent(
|
||||||
@ -287,24 +294,24 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
action: {
|
action: {
|
||||||
if "".isEmpty {
|
// if "".isEmpty {
|
||||||
component.openPeer(peer)
|
// component.openPeer(peer)
|
||||||
Queue.mainQueue().after(1.0, {
|
// Queue.mainQueue().after(1.0, {
|
||||||
component.cancel(false)
|
// component.cancel(false)
|
||||||
})
|
// })
|
||||||
} else {
|
// } else {
|
||||||
if let controller = controller() as? GiftViewScreen, let navigationController = controller.navigationController, let chatController = navigationController.viewControllers.first(where: { $0 is ChatController }) as? ChatController {
|
if let controller = controller() as? GiftViewScreen, let navigationController = controller.navigationController, let chatController = navigationController.viewControllers.first(where: { $0 is ChatController }) as? ChatController {
|
||||||
chatController.playShakeAnimation()
|
chatController.playShakeAnimation()
|
||||||
}
|
}
|
||||||
component.cancel(true)
|
component.cancel(true)
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
tableItems.append(.init(
|
tableItems.append(.init(
|
||||||
id: "from",
|
id: "from_anon",
|
||||||
title: strings.Stars_Transaction_From,
|
title: strings.Stars_Transaction_From,
|
||||||
component: AnyComponent(
|
component: AnyComponent(
|
||||||
PeerCellComponent(
|
PeerCellComponent(
|
||||||
@ -430,6 +437,8 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: descriptionOrigin + description.size.height / 2.0))
|
.position(CGPoint(x: context.availableSize.width / 2.0, y: descriptionOrigin + description.size.height / 2.0))
|
||||||
)
|
)
|
||||||
originY += description.size.height + 10.0
|
originY += description.size.height + 10.0
|
||||||
|
} else {
|
||||||
|
originY += 11.0
|
||||||
}
|
}
|
||||||
|
|
||||||
let amountSpacing: CGFloat = 1.0
|
let amountSpacing: CGFloat = 1.0
|
||||||
@ -439,7 +448,11 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||||||
var amountOrigin = originY
|
var amountOrigin = originY
|
||||||
if "".isEmpty {
|
if "".isEmpty {
|
||||||
amountOrigin -= descriptionSize.height + 10.0
|
amountOrigin -= descriptionSize.height + 10.0
|
||||||
originY += amount.size.height + 26.0
|
if descriptionSize.height > 0 {
|
||||||
|
originY += amount.size.height + 26.0
|
||||||
|
} else {
|
||||||
|
originY += amount.size.height + 2.0
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
originY += amount.size.height + 20.0
|
originY += amount.size.height + 20.0
|
||||||
}
|
}
|
||||||
@ -696,14 +709,14 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||||||
case message(EngineMessage)
|
case message(EngineMessage)
|
||||||
case profileGift(EnginePeer.Id, ProfileGiftsContext.State.StarGift)
|
case profileGift(EnginePeer.Id, ProfileGiftsContext.State.StarGift)
|
||||||
|
|
||||||
var arguments: (peerId: EnginePeer.Id, fromPeerName: String?, messageId: EngineMessage.Id?, incoming: Bool, gift: StarGift, convertStars: Int64, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, converted: Bool)? {
|
var arguments: (peerId: EnginePeer.Id, fromPeerId: EnginePeer.Id?, fromPeerName: String?, messageId: EngineMessage.Id?, incoming: Bool, gift: StarGift, convertStars: Int64, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, converted: Bool)? {
|
||||||
switch self {
|
switch self {
|
||||||
case let .message(message):
|
case let .message(message):
|
||||||
if let action = message.media.first(where: { $0 is TelegramMediaAction }) as? TelegramMediaAction, case let .starGift(gift, convertStars, text, entities, nameHidden, savedToProfile, converted) = action.action {
|
if let action = message.media.first(where: { $0 is TelegramMediaAction }) as? TelegramMediaAction, case let .starGift(gift, convertStars, text, entities, nameHidden, savedToProfile, converted) = action.action {
|
||||||
return (message.id.peerId, message.author?.compactDisplayTitle, message.id, message.flags.contains(.Incoming), gift, convertStars, text, entities, nameHidden, savedToProfile, converted)
|
return (message.id.peerId, message.author?.id, message.author?.compactDisplayTitle, message.id, message.flags.contains(.Incoming), gift, convertStars, text, entities, nameHidden, savedToProfile, converted)
|
||||||
}
|
}
|
||||||
case let .profileGift(peerId, gift):
|
case let .profileGift(peerId, gift):
|
||||||
return (peerId, gift.fromPeer?.compactDisplayTitle, gift.messageId, false, gift.gift, gift.convertStars ?? 0, gift.text, gift.entities, gift.nameHidden, gift.savedToProfile, false)
|
return (peerId, gift.fromPeer?.id, gift.fromPeer?.compactDisplayTitle, gift.messageId, false, gift.gift, gift.convertStars ?? 0, gift.text, gift.entities, gift.nameHidden, gift.savedToProfile, false)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -792,9 +805,25 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||||||
presentationData: presentationData,
|
presentationData: presentationData,
|
||||||
content: .sticker(context: context, file: arguments.gift.file, loop: false, title: added ? "Gift Saved to Profile" : "Gift Removed from Profile", text: added ? "The gift is now displayed in [your profile]()." : "The gift is no longer displayed in [your profile]().", undoText: nil, customAction: nil),
|
content: .sticker(context: context, file: arguments.gift.file, loop: false, title: added ? "Gift Saved to Profile" : "Gift Removed from Profile", text: added ? "The gift is now displayed in [your profile]()." : "The gift is no longer displayed in [your profile]().", undoText: nil, customAction: nil),
|
||||||
elevatedLayout: lastController is ChatController,
|
elevatedLayout: lastController is ChatController,
|
||||||
action: { action in
|
action: { [weak navigationController] action in
|
||||||
if case .info = action {
|
if case .info = action, let navigationController {
|
||||||
|
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak navigationController] peer in
|
||||||
|
guard let peer, let navigationController else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let controller = context.sharedContext.makePeerInfoController(
|
||||||
|
context: context,
|
||||||
|
updatedPresentationData: nil,
|
||||||
|
peer: peer._asPeer(),
|
||||||
|
mode: .myProfileGifts,
|
||||||
|
avatarInitiallyExpanded: false,
|
||||||
|
fromChat: false,
|
||||||
|
requestsContext: nil
|
||||||
|
) {
|
||||||
|
navigationController.pushViewController(controller, animated: true)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -823,8 +852,12 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||||||
|> deliverOnMainQueue).startStandalone()
|
|> deliverOnMainQueue).startStandalone()
|
||||||
}
|
}
|
||||||
self?.dismissAnimated()
|
self?.dismissAnimated()
|
||||||
|
|
||||||
if let navigationController {
|
if let navigationController {
|
||||||
|
if let starsContext = context.starsContext {
|
||||||
|
navigationController.pushViewController(context.sharedContext.makeStarsTransactionsScreen(context: context, starsContext: starsContext), animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
Queue.mainQueue().after(0.5) {
|
Queue.mainQueue().after(0.5) {
|
||||||
if let lastController = navigationController.viewControllers.last as? ViewController {
|
if let lastController = navigationController.viewControllers.last as? ViewController {
|
||||||
let resultController = UndoOverlayController(
|
let resultController = UndoOverlayController(
|
||||||
|
@ -41,17 +41,20 @@ public final class ListSectionContentView: UIView {
|
|||||||
|
|
||||||
public final class Configuration {
|
public final class Configuration {
|
||||||
public let theme: PresentationTheme
|
public let theme: PresentationTheme
|
||||||
|
public let isModal: Bool
|
||||||
public let displaySeparators: Bool
|
public let displaySeparators: Bool
|
||||||
public let extendsItemHighlightToSection: Bool
|
public let extendsItemHighlightToSection: Bool
|
||||||
public let background: ListSectionComponent.Background
|
public let background: ListSectionComponent.Background
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
theme: PresentationTheme,
|
theme: PresentationTheme,
|
||||||
|
isModal: Bool = false,
|
||||||
displaySeparators: Bool,
|
displaySeparators: Bool,
|
||||||
extendsItemHighlightToSection: Bool,
|
extendsItemHighlightToSection: Bool,
|
||||||
background: ListSectionComponent.Background
|
background: ListSectionComponent.Background
|
||||||
) {
|
) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
|
self.isModal = isModal
|
||||||
self.displaySeparators = displaySeparators
|
self.displaySeparators = displaySeparators
|
||||||
self.extendsItemHighlightToSection = extendsItemHighlightToSection
|
self.extendsItemHighlightToSection = extendsItemHighlightToSection
|
||||||
self.background = background
|
self.background = background
|
||||||
@ -116,7 +119,7 @@ public final class ListSectionContentView: UIView {
|
|||||||
backgroundColor = configuration.theme.list.itemHighlightedBackgroundColor
|
backgroundColor = configuration.theme.list.itemHighlightedBackgroundColor
|
||||||
} else {
|
} else {
|
||||||
transition = .easeInOut(duration: 0.2)
|
transition = .easeInOut(duration: 0.2)
|
||||||
backgroundColor = configuration.theme.list.itemBlocksBackgroundColor
|
backgroundColor = configuration.isModal ? configuration.theme.list.itemModalBlocksBackgroundColor : configuration.theme.list.itemBlocksBackgroundColor
|
||||||
}
|
}
|
||||||
|
|
||||||
self.externalContentBackgroundView.updateColor(color: backgroundColor, transition: transition)
|
self.externalContentBackgroundView.updateColor(color: backgroundColor, transition: transition)
|
||||||
@ -144,7 +147,7 @@ public final class ListSectionContentView: UIView {
|
|||||||
if self.highlightedItemId != nil && configuration.extendsItemHighlightToSection {
|
if self.highlightedItemId != nil && configuration.extendsItemHighlightToSection {
|
||||||
backgroundColor = configuration.theme.list.itemHighlightedBackgroundColor
|
backgroundColor = configuration.theme.list.itemHighlightedBackgroundColor
|
||||||
} else {
|
} else {
|
||||||
backgroundColor = configuration.theme.list.itemBlocksBackgroundColor
|
backgroundColor = configuration.isModal ? configuration.theme.list.itemModalBlocksBackgroundColor : configuration.theme.list.itemBlocksBackgroundColor
|
||||||
}
|
}
|
||||||
self.externalContentBackgroundView.updateColor(color: backgroundColor, transition: transition)
|
self.externalContentBackgroundView.updateColor(color: backgroundColor, transition: transition)
|
||||||
|
|
||||||
@ -305,6 +308,7 @@ public final class ListSectionComponent: Component {
|
|||||||
public let header: AnyComponent<Empty>?
|
public let header: AnyComponent<Empty>?
|
||||||
public let footer: AnyComponent<Empty>?
|
public let footer: AnyComponent<Empty>?
|
||||||
public let items: [AnyComponentWithIdentity<Empty>]
|
public let items: [AnyComponentWithIdentity<Empty>]
|
||||||
|
public let isModal: Bool
|
||||||
public let displaySeparators: Bool
|
public let displaySeparators: Bool
|
||||||
public let extendsItemHighlightToSection: Bool
|
public let extendsItemHighlightToSection: Bool
|
||||||
|
|
||||||
@ -314,6 +318,7 @@ public final class ListSectionComponent: Component {
|
|||||||
header: AnyComponent<Empty>?,
|
header: AnyComponent<Empty>?,
|
||||||
footer: AnyComponent<Empty>?,
|
footer: AnyComponent<Empty>?,
|
||||||
items: [AnyComponentWithIdentity<Empty>],
|
items: [AnyComponentWithIdentity<Empty>],
|
||||||
|
isModal: Bool = false,
|
||||||
displaySeparators: Bool = true,
|
displaySeparators: Bool = true,
|
||||||
extendsItemHighlightToSection: Bool = false
|
extendsItemHighlightToSection: Bool = false
|
||||||
) {
|
) {
|
||||||
@ -322,6 +327,7 @@ public final class ListSectionComponent: Component {
|
|||||||
self.header = header
|
self.header = header
|
||||||
self.footer = footer
|
self.footer = footer
|
||||||
self.items = items
|
self.items = items
|
||||||
|
self.isModal = isModal
|
||||||
self.displaySeparators = displaySeparators
|
self.displaySeparators = displaySeparators
|
||||||
self.extendsItemHighlightToSection = extendsItemHighlightToSection
|
self.extendsItemHighlightToSection = extendsItemHighlightToSection
|
||||||
}
|
}
|
||||||
@ -342,6 +348,9 @@ public final class ListSectionComponent: Component {
|
|||||||
if lhs.items != rhs.items {
|
if lhs.items != rhs.items {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.isModal != rhs.isModal {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.displaySeparators != rhs.displaySeparators {
|
if lhs.displaySeparators != rhs.displaySeparators {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -448,6 +457,7 @@ public final class ListSectionComponent: Component {
|
|||||||
let contentResult = self.contentView.update(
|
let contentResult = self.contentView.update(
|
||||||
configuration: ListSectionContentView.Configuration(
|
configuration: ListSectionContentView.Configuration(
|
||||||
theme: component.theme,
|
theme: component.theme,
|
||||||
|
isModal: component.isModal,
|
||||||
displaySeparators: component.displaySeparators,
|
displaySeparators: component.displaySeparators,
|
||||||
extendsItemHighlightToSection: component.extendsItemHighlightToSection,
|
extendsItemHighlightToSection: component.extendsItemHighlightToSection,
|
||||||
background: component.background
|
background: component.background
|
||||||
@ -522,17 +532,20 @@ public final class ListSubSectionComponent: Component {
|
|||||||
public let theme: PresentationTheme
|
public let theme: PresentationTheme
|
||||||
public let leftInset: CGFloat
|
public let leftInset: CGFloat
|
||||||
public let items: [AnyComponentWithIdentity<Empty>]
|
public let items: [AnyComponentWithIdentity<Empty>]
|
||||||
|
public let isModal: Bool
|
||||||
public let displaySeparators: Bool
|
public let displaySeparators: Bool
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
theme: PresentationTheme,
|
theme: PresentationTheme,
|
||||||
leftInset: CGFloat,
|
leftInset: CGFloat,
|
||||||
items: [AnyComponentWithIdentity<Empty>],
|
items: [AnyComponentWithIdentity<Empty>],
|
||||||
|
isModal: Bool = false,
|
||||||
displaySeparators: Bool = true
|
displaySeparators: Bool = true
|
||||||
) {
|
) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.leftInset = leftInset
|
self.leftInset = leftInset
|
||||||
self.items = items
|
self.items = items
|
||||||
|
self.isModal = isModal
|
||||||
self.displaySeparators = displaySeparators
|
self.displaySeparators = displaySeparators
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -546,6 +559,9 @@ public final class ListSubSectionComponent: Component {
|
|||||||
if lhs.items != rhs.items {
|
if lhs.items != rhs.items {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.isModal != rhs.isModal {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.displaySeparators != rhs.displaySeparators {
|
if lhs.displaySeparators != rhs.displaySeparators {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -615,6 +631,7 @@ public final class ListSubSectionComponent: Component {
|
|||||||
let contentResult = self.contentView.update(
|
let contentResult = self.contentView.update(
|
||||||
configuration: ListSectionContentView.Configuration(
|
configuration: ListSectionContentView.Configuration(
|
||||||
theme: component.theme,
|
theme: component.theme,
|
||||||
|
isModal: component.isModal,
|
||||||
displaySeparators: component.displaySeparators,
|
displaySeparators: component.displaySeparators,
|
||||||
extendsItemHighlightToSection: false,
|
extendsItemHighlightToSection: false,
|
||||||
background: .none(clipped: false)
|
background: .none(clipped: false)
|
||||||
|
@ -8250,9 +8250,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func openReport(type: PeerInfoReportType, contextController: ContextControllerProtocol?, backAction: ((ContextControllerProtocol) -> Void)?) {
|
private func openReport(type: PeerInfoReportType, contextController: ContextControllerProtocol?, backAction: ((ContextControllerProtocol) -> Void)?) {
|
||||||
guard let controller = self.controller else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.view.endEditing(true)
|
self.view.endEditing(true)
|
||||||
|
|
||||||
switch type {
|
switch type {
|
||||||
@ -8291,20 +8288,28 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
])
|
])
|
||||||
self.controller?.present(actionSheet, in: .window(.root))
|
self.controller?.present(actionSheet, in: .window(.root))
|
||||||
default:
|
default:
|
||||||
let options: [PeerReportOption]
|
contextController?.dismiss()
|
||||||
if case .user = type {
|
|
||||||
options = [.spam, .fake, .violence, .pornography, .childAbuse]
|
|
||||||
} else {
|
|
||||||
options = [.spam, .fake, .violence, .pornography, .childAbuse, .copyright, .other]
|
|
||||||
}
|
|
||||||
|
|
||||||
presentPeerReportOptions(context: self.context, parent: controller, contextController: contextController, backAction: backAction, subject: .peer(self.peerId), options: options, passthrough: true, completion: { [weak self] reason, _ in
|
self.context.sharedContext.makeContentReportScreen(context: self.context, subject: .peer(self.peerId), forceDark: false, present: { [weak self] controller in
|
||||||
if let reason = reason {
|
self?.controller?.push(controller)
|
||||||
DispatchQueue.main.async {
|
}, completion: {
|
||||||
self?.openChatForReporting(reason)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// let options: [PeerReportOption]
|
||||||
|
// if case .user = type {
|
||||||
|
// options = [.spam, .fake, .violence, .pornography, .childAbuse]
|
||||||
|
// } else {
|
||||||
|
// options = [.spam, .fake, .violence, .pornography, .childAbuse, .copyright, .other]
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// presentPeerReportOptions(context: self.context, parent: controller, contextController: contextController, backAction: backAction, subject: .peer(self.peerId), options: options, passthrough: true, completion: { [weak self] reason, _ in
|
||||||
|
// if let reason = reason {
|
||||||
|
// DispatchQueue.main.async {
|
||||||
|
// self?.openChatForReporting(reason)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11645,13 +11650,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
}
|
}
|
||||||
strongSelf.view.endEditing(true)
|
strongSelf.view.endEditing(true)
|
||||||
|
|
||||||
strongSelf.controller?.present(peerReportOptionsController(context: strongSelf.context, subject: .messages(Array(messageIds).sorted()), passthrough: false, present: { c, a in
|
strongSelf.context.sharedContext.makeContentReportScreen(context: strongSelf.context, subject: .messages(Array(messageIds).sorted()), forceDark: false, present: { [weak self] controller in
|
||||||
self?.controller?.present(c, in: .window(.root), with: a)
|
self?.controller?.push(controller)
|
||||||
}, push: { c in
|
}, completion: {})
|
||||||
self?.controller?.push(c)
|
|
||||||
}, completion: { _, _ in }), in: .window(.root))
|
|
||||||
|
|
||||||
|
|
||||||
}, displayCopyProtectionTip: { [weak self] node, save in
|
}, displayCopyProtectionTip: { [weak self] node, save in
|
||||||
if let strongSelf = self, let peer = strongSelf.data?.peer, let messageIds = strongSelf.state.selectedMessageIds, !messageIds.isEmpty {
|
if let strongSelf = self, let peer = strongSelf.data?.peer, let messageIds = strongSelf.state.selectedMessageIds, !messageIds.isEmpty {
|
||||||
let _ = (strongSelf.context.engine.data.get(EngineDataMap(
|
let _ = (strongSelf.context.engine.data.get(EngineDataMap(
|
||||||
@ -12284,6 +12285,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||||||
private weak var requestsContext: PeerInvitationImportersContext?
|
private weak var requestsContext: PeerInvitationImportersContext?
|
||||||
fileprivate let starsContext: StarsContext?
|
fileprivate let starsContext: StarsContext?
|
||||||
private let switchToRecommendedChannels: Bool
|
private let switchToRecommendedChannels: Bool
|
||||||
|
private let switchToGifts: Bool
|
||||||
private let chatLocation: ChatLocation
|
private let chatLocation: ChatLocation
|
||||||
private let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
private let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
||||||
|
|
||||||
@ -12340,7 +12342,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||||||
|
|
||||||
private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
|
private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
|
||||||
|
|
||||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool = false, isMyProfile: Bool = false, hintGroupInCommon: PeerId? = nil, requestsContext: PeerInvitationImportersContext? = nil, forumTopicThread: ChatReplyThreadMessage? = nil, switchToRecommendedChannels: Bool = false) {
|
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool = false, isMyProfile: Bool = false, hintGroupInCommon: PeerId? = nil, requestsContext: PeerInvitationImportersContext? = nil, forumTopicThread: ChatReplyThreadMessage? = nil, switchToRecommendedChannels: Bool = false, switchToGifts: Bool = false) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.updatedPresentationData = updatedPresentationData
|
self.updatedPresentationData = updatedPresentationData
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
@ -12354,6 +12356,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||||||
self.hintGroupInCommon = hintGroupInCommon
|
self.hintGroupInCommon = hintGroupInCommon
|
||||||
self.requestsContext = requestsContext
|
self.requestsContext = requestsContext
|
||||||
self.switchToRecommendedChannels = switchToRecommendedChannels
|
self.switchToRecommendedChannels = switchToRecommendedChannels
|
||||||
|
self.switchToGifts = switchToGifts
|
||||||
|
|
||||||
if let forumTopicThread = forumTopicThread {
|
if let forumTopicThread = forumTopicThread {
|
||||||
self.chatLocation = .replyThread(message: forumTopicThread)
|
self.chatLocation = .replyThread(message: forumTopicThread)
|
||||||
@ -12694,7 +12697,13 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||||||
}
|
}
|
||||||
|
|
||||||
override public func loadDisplayNode() {
|
override public func loadDisplayNode() {
|
||||||
self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, isSettings: self.isSettings, isMyProfile: self.isMyProfile, hintGroupInCommon: self.hintGroupInCommon, requestsContext: self.requestsContext, starsContext: self.starsContext, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, initialPaneKey: self.switchToRecommendedChannels ? .recommended : nil)
|
var initialPaneKey: PeerInfoPaneKey?
|
||||||
|
if self.switchToRecommendedChannels {
|
||||||
|
initialPaneKey = .recommended
|
||||||
|
} else if self.switchToGifts {
|
||||||
|
initialPaneKey = .gifts
|
||||||
|
}
|
||||||
|
self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, isSettings: self.isSettings, isMyProfile: self.isMyProfile, hintGroupInCommon: self.hintGroupInCommon, requestsContext: self.requestsContext, starsContext: self.starsContext, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, initialPaneKey: initialPaneKey)
|
||||||
self.controllerNode.accountsAndPeers.set(self.accountsAndPeers.get() |> map { $0.1 })
|
self.controllerNode.accountsAndPeers.set(self.accountsAndPeers.get() |> map { $0.1 })
|
||||||
self.controllerNode.activeSessionsContextAndCount.set(self.activeSessionsContextAndCount.get())
|
self.controllerNode.activeSessionsContextAndCount.set(self.activeSessionsContextAndCount.get())
|
||||||
self.cachedDataPromise.set(self.controllerNode.cachedDataPromise.get())
|
self.cachedDataPromise.set(self.controllerNode.cachedDataPromise.get())
|
||||||
|
@ -87,6 +87,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
let isFirstTime = starsProducts == nil
|
||||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
self.statusPromise.set(.single(PeerInfoStatusData(text: presentationData.strings.SharedMedia_GiftCount(state.count ?? 0), isActivity: true, key: .gifts)))
|
self.statusPromise.set(.single(PeerInfoStatusData(text: presentationData.strings.SharedMedia_GiftCount(state.count ?? 0), isActivity: true, key: .gifts)))
|
||||||
self.starsProducts = state.gifts
|
self.starsProducts = state.gifts
|
||||||
@ -96,7 +97,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
self.ready.set(.single(true))
|
self.ready.set(.single(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.updateScrolling()
|
self.updateScrolling(transition: isFirstTime ? .immediate : .easeInOut(duration: 0.25))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,10 +120,10 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||||
self.updateScrolling()
|
self.updateScrolling(transition: .immediate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateScrolling() {
|
func updateScrolling(transition: ComponentTransition) {
|
||||||
if let starsProducts = self.starsProducts, let params = self.currentParams {
|
if let starsProducts = self.starsProducts, let params = self.currentParams {
|
||||||
let optionSpacing: CGFloat = 10.0
|
let optionSpacing: CGFloat = 10.0
|
||||||
let sideInset = params.sideInset + 16.0
|
let sideInset = params.sideInset + 16.0
|
||||||
@ -140,13 +141,14 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
let itemId = AnyHashable(product.date)
|
let itemId = AnyHashable(product.date)
|
||||||
validIds.append(itemId)
|
validIds.append(itemId)
|
||||||
|
|
||||||
let itemTransition = ComponentTransition.immediate
|
var itemTransition = transition
|
||||||
let visibleItem: ComponentView<Empty>
|
let visibleItem: ComponentView<Empty>
|
||||||
if let current = self.starsItems[itemId] {
|
if let current = self.starsItems[itemId] {
|
||||||
visibleItem = current
|
visibleItem = current
|
||||||
} else {
|
} else {
|
||||||
visibleItem = ComponentView()
|
visibleItem = ComponentView()
|
||||||
self.starsItems[itemId] = visibleItem
|
self.starsItems[itemId] = visibleItem
|
||||||
|
itemTransition = .immediate
|
||||||
}
|
}
|
||||||
|
|
||||||
var isVisible = false
|
var isVisible = false
|
||||||
@ -221,6 +223,26 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var removeIds: [AnyHashable] = []
|
||||||
|
for (id, item) in self.starsItems {
|
||||||
|
if !validIds.contains(id) {
|
||||||
|
removeIds.append(id)
|
||||||
|
if let itemView = item.view {
|
||||||
|
if !transition.animation.isImmediate {
|
||||||
|
itemView.layer.animateScale(from: 1.0, to: 0.01, duration: 0.25, removeOnCompletion: false)
|
||||||
|
itemView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
|
||||||
|
itemView.removeFromSuperview()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
itemView.removeFromSuperview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for id in removeIds {
|
||||||
|
self.starsItems.removeValue(forKey: id)
|
||||||
|
}
|
||||||
|
|
||||||
var contentHeight = ceil(CGFloat(starsProducts.count) / 3.0) * starsOptionSize.height + 60.0 + 16.0
|
var contentHeight = ceil(CGFloat(starsProducts.count) / 3.0) * starsOptionSize.height + 60.0 + 16.0
|
||||||
|
|
||||||
if self.peerId == self.context.account.peerId {
|
if self.peerId == self.context.account.peerId {
|
||||||
@ -354,7 +376,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
}
|
}
|
||||||
self.scrollNode.view.isScrollEnabled = !isScrollingLockedAtTop
|
self.scrollNode.view.isScrollEnabled = !isScrollingLockedAtTop
|
||||||
|
|
||||||
self.updateScrolling()
|
self.updateScrolling(transition: ComponentTransition(transition))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func findLoadedMessage(id: MessageId) -> Message? {
|
public func findLoadedMessage(id: MessageId) -> Message? {
|
||||||
|
@ -1037,7 +1037,7 @@ public final class StarsTransactionsScreen: ViewControllerComponentContainer {
|
|||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let controller = self.context.sharedContext.makePremiumGiftController(context: self.context, source: .stars(birthdays), completion: { [weak self] peerIds in
|
let controller = self.context.sharedContext.makeStarsGiftController(context: self.context, birthdays: birthdays, completion: { [weak self] peerIds in
|
||||||
guard let self, let peerId = peerIds.first else {
|
guard let self, let peerId = peerIds.first else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -741,6 +741,9 @@ public final class TextFieldComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.insertText(NSAttributedString(string: insertString))
|
self.insertText(NSAttributedString(string: insertString))
|
||||||
|
} else if (range.length == 0 && text == "\n"), let returnKeyAction = component.returnKeyAction {
|
||||||
|
returnKeyAction()
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -2204,6 +2204,75 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
return PremiumLimitScreen(context: context, subject: mappedSubject, count: count, forceDark: forceDark, cancel: cancel, action: action)
|
return PremiumLimitScreen(context: context, subject: mappedSubject, count: count, forceDark: forceDark, cancel: cancel, action: action)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func makeStarsGiftController(context: AccountContext, birthdays: [EnginePeer.Id: TelegramBirthday]?, completion: @escaping (([EnginePeer.Id]) -> Void)) -> ViewController {
|
||||||
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
|
var presentBirthdayPickerImpl: (() -> Void)?
|
||||||
|
let starsMode: ContactSelectionControllerMode = .starsGifting(birthdays: birthdays, hasActions: false)
|
||||||
|
|
||||||
|
let contactOptions: Signal<[ContactListAdditionalOption], NoError> = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Birthday(id: context.account.peerId))
|
||||||
|
|> map { birthday in
|
||||||
|
if birthday == nil {
|
||||||
|
return [ContactListAdditionalOption(
|
||||||
|
title: presentationData.strings.Premium_Gift_ContactSelection_AddBirthday,
|
||||||
|
icon: .generic(UIImage(bundleImageName: "Contact List/AddBirthdayIcon")!),
|
||||||
|
action: {
|
||||||
|
presentBirthdayPickerImpl?()
|
||||||
|
},
|
||||||
|
clearHighlightAutomatically: true
|
||||||
|
)]
|
||||||
|
} else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> deliverOnMainQueue
|
||||||
|
|
||||||
|
let options = Promise<[StarsGiftOption]>()
|
||||||
|
options.set(context.engine.payments.starsGiftOptions(peerId: nil))
|
||||||
|
let controller = context.sharedContext.makeContactSelectionController(ContactSelectionControllerParams(
|
||||||
|
context: context,
|
||||||
|
mode: starsMode,
|
||||||
|
autoDismiss: false,
|
||||||
|
title: { strings in return strings.Stars_Purchase_GiftStars },
|
||||||
|
options: contactOptions
|
||||||
|
))
|
||||||
|
let _ = (controller.result
|
||||||
|
|> deliverOnMainQueue).start(next: { result in
|
||||||
|
if let (peers, _, _, _, _, _) = result, let contactPeer = peers.first, case let .peer(peer, _, _) = contactPeer {
|
||||||
|
completion([peer.id])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
presentBirthdayPickerImpl = { [weak controller] in
|
||||||
|
guard let controller else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let _ = context.engine.notices.dismissServerProvidedSuggestion(suggestion: .setupBirthday).startStandalone()
|
||||||
|
|
||||||
|
let settingsPromise: Promise<AccountPrivacySettings?>
|
||||||
|
if let rootController = context.sharedContext.mainWindow?.viewController as? TelegramRootControllerInterface, let current = rootController.getPrivacySettings() {
|
||||||
|
settingsPromise = current
|
||||||
|
} else {
|
||||||
|
settingsPromise = Promise()
|
||||||
|
settingsPromise.set(.single(nil) |> then(context.engine.privacy.requestAccountPrivacySettings() |> map(Optional.init)))
|
||||||
|
}
|
||||||
|
let birthdayController = BirthdayPickerScreen(context: context, settings: settingsPromise.get(), openSettings: {
|
||||||
|
context.sharedContext.makeBirthdayPrivacyController(context: context, settings: settingsPromise, openedFromBirthdayScreen: true, present: { [weak controller] c in
|
||||||
|
controller?.push(c)
|
||||||
|
})
|
||||||
|
}, completion: { [weak controller] value in
|
||||||
|
let _ = context.engine.accountData.updateBirthday(birthday: value).startStandalone()
|
||||||
|
|
||||||
|
controller?.present(UndoOverlayController(presentationData: presentationData, content: .actionSucceeded(title: nil, text: presentationData.strings.Birthday_Added, cancel: nil, destructive: false), elevatedLayout: false, action: { _ in
|
||||||
|
return true
|
||||||
|
}), in: .current)
|
||||||
|
})
|
||||||
|
controller.push(birthdayController)
|
||||||
|
}
|
||||||
|
|
||||||
|
return controller
|
||||||
|
}
|
||||||
|
|
||||||
public func makePremiumGiftController(context: AccountContext, source: PremiumGiftSource, completion: (([EnginePeer.Id]) -> Void)?) -> ViewController {
|
public func makePremiumGiftController(context: AccountContext, source: PremiumGiftSource, completion: (([EnginePeer.Id]) -> Void)?) -> ViewController {
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
@ -2247,122 +2316,37 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
var sendMessageImpl: ((EnginePeer) -> Void)?
|
var sendMessageImpl: ((EnginePeer) -> Void)?
|
||||||
|
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
let controller: ViewController
|
let options = Promise<[PremiumGiftCodeOption]>()
|
||||||
// if case .stars = source {
|
options.set(context.engine.payments.premiumGiftCodeOptions(peerId: nil))
|
||||||
// let options = Promise<[StarsGiftOption]>()
|
let controller = context.sharedContext.makeContactSelectionController(ContactSelectionControllerParams(
|
||||||
// options.set(context.engine.payments.starsGiftOptions(peerId: nil))
|
context: context,
|
||||||
let options = Promise<[PremiumGiftCodeOption]>()
|
mode: starsMode,
|
||||||
options.set(context.engine.payments.premiumGiftCodeOptions(peerId: nil))
|
autoDismiss: false,
|
||||||
let contactsController = context.sharedContext.makeContactSelectionController(ContactSelectionControllerParams(
|
title: { strings in return "Gift Premium or Stars" },
|
||||||
context: context,
|
options: contactOptions,
|
||||||
mode: starsMode,
|
openProfile: { peer in
|
||||||
autoDismiss: false,
|
openProfileImpl?(peer)
|
||||||
title: { strings in return "Gift Premium or Stars" },
|
},
|
||||||
options: contactOptions,
|
sendMessage: { peer in
|
||||||
openProfile: { peer in
|
sendMessageImpl?(peer)
|
||||||
openProfileImpl?(peer)
|
}
|
||||||
},
|
))
|
||||||
sendMessage: { peer in
|
let _ = combineLatest(queue: Queue.mainQueue(), contactsController.result, options.get())
|
||||||
sendMessageImpl?(peer)
|
.startStandalone(next: { [weak controller] result, options in
|
||||||
}
|
if let (peers, _, _, _, _, _) = result, let contactPeer = peers.first, case let .peer(peer, _, _) = contactPeer, let starsContext = context.starsContext {
|
||||||
))
|
let premiumOptions = options.filter { $0.users == 1 }.map { CachedPremiumGiftOption(months: $0.months, currency: $0.currency, amount: $0.amount, botUrl: "", storeProductId: $0.storeProductId) }
|
||||||
let _ = combineLatest(queue: Queue.mainQueue(), contactsController.result, options.get())
|
let giftController = GiftOptionsScreen(context: context, starsContext: starsContext, peerId: peer.id, premiumOptions: premiumOptions)
|
||||||
.startStandalone(next: { [weak contactsController] result, options in
|
giftController.navigationPresentation = .modal
|
||||||
if let (peers, _, _, _, _, _) = result, let contactPeer = peers.first, case let .peer(peer, _, _) = contactPeer, let starsContext = context.starsContext {
|
controller?.push(giftController)
|
||||||
let premiumOptions = options.filter { $0.users == 1 }.map { CachedPremiumGiftOption(months: $0.months, currency: $0.currency, amount: $0.amount, botUrl: "", storeProductId: $0.storeProductId) }
|
|
||||||
let giftController = GiftOptionsScreen(context: context, starsContext: starsContext, peerId: peer.id, premiumOptions: premiumOptions)
|
|
||||||
giftController.navigationPresentation = .modal
|
|
||||||
contactsController?.push(giftController)
|
|
||||||
|
|
||||||
// completion?([peer.id])
|
// completion?([peer.id])
|
||||||
|
|
||||||
if case .chatList = source, let _ = currentBirthdays {
|
if case .chatList = source, let _ = currentBirthdays {
|
||||||
let _ = context.engine.notices.dismissServerProvidedSuggestion(suggestion: .todayBirthdays).startStandalone()
|
let _ = context.engine.notices.dismissServerProvidedSuggestion(suggestion: .todayBirthdays).startStandalone()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
controller = contactsController
|
})
|
||||||
// } else {
|
|
||||||
// let options = Promise<[PremiumGiftCodeOption]>()
|
|
||||||
// options.set(context.engine.payments.premiumGiftCodeOptions(peerId: nil))
|
|
||||||
// let contactsController = context.sharedContext.makeContactMultiselectionController(
|
|
||||||
// ContactMultiselectionControllerParams(
|
|
||||||
// context: context,
|
|
||||||
// mode: mode,
|
|
||||||
// options: contactOptions,
|
|
||||||
// isPeerEnabled: { peer in
|
|
||||||
// if case let .user(user) = peer, user.botInfo == nil && !peer.isService && !user.flags.contains(.isSupport) {
|
|
||||||
// return true
|
|
||||||
// } else {
|
|
||||||
// return false
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// limit: limit,
|
|
||||||
// reachedLimit: { limit in
|
|
||||||
// reachedLimitImpl?(limit)
|
|
||||||
// },
|
|
||||||
// openProfile: { peer in
|
|
||||||
// openProfileImpl?(peer)
|
|
||||||
// },
|
|
||||||
// sendMessage: { peer in
|
|
||||||
// sendMessageImpl?(peer)
|
|
||||||
// }
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// let _ = combineLatest(queue: Queue.mainQueue(), contactsController.result, options.get())
|
|
||||||
// .startStandalone(next: { [weak contactsController] result, options in
|
|
||||||
// guard let controller = contactsController else {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// var peerIds: [PeerId] = []
|
|
||||||
// if case let .result(peerIdsValue, _) = result {
|
|
||||||
// peerIds = peerIdsValue.compactMap({ peerId in
|
|
||||||
// if case let .peer(peerId) = peerId {
|
|
||||||
// return peerId
|
|
||||||
// } else {
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// guard !peerIds.isEmpty else {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// let mappedOptions = options.filter { $0.users == 1 }.map { CachedPremiumGiftOption(months: $0.months, currency: $0.currency, amount: $0.amount, botUrl: "", storeProductId: $0.storeProductId) }
|
|
||||||
// var pushImpl: ((ViewController) -> Void)?
|
|
||||||
// var filterImpl: (() -> Void)?
|
|
||||||
// let giftController = PremiumGiftScreen(context: context, peerIds: peerIds, options: mappedOptions, source: source, pushController: { c in
|
|
||||||
// pushImpl?(c)
|
|
||||||
// }, completion: {
|
|
||||||
// filterImpl?()
|
|
||||||
//
|
|
||||||
// if case .chatList = source, let _ = currentBirthdays {
|
|
||||||
// let _ = context.engine.notices.dismissServerProvidedSuggestion(suggestion: .todayBirthdays).startStandalone()
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// pushImpl = { [weak giftController] c in
|
|
||||||
// giftController?.push(c)
|
|
||||||
// }
|
|
||||||
// filterImpl = { [weak giftController] in
|
|
||||||
// if let navigationController = giftController?.navigationController as? NavigationController {
|
|
||||||
// var controllers = navigationController.viewControllers
|
|
||||||
// controllers = controllers.filter { !($0 is ContactMultiselectionController) && !($0 is PremiumGiftScreen) }
|
|
||||||
// navigationController.setViewControllers(controllers, animated: true)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// controller.push(giftController)
|
|
||||||
// })
|
|
||||||
// controller = contactsController
|
|
||||||
// }
|
|
||||||
|
|
||||||
// reachedLimitImpl = { [weak controller] limit in
|
|
||||||
// guard let controller else {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// HapticFeedback().error()
|
|
||||||
// controller.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.Premium_Gift_ContactSelection_MaximumReached("\(limit)").string, timeout: nil, customUndoText: nil), elevatedLayout: true, position: .bottom, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
|
||||||
// }
|
|
||||||
|
|
||||||
sendMessageImpl = { [weak self, weak controller] peer in
|
sendMessageImpl = { [weak self, weak controller] peer in
|
||||||
guard let self, let controller, let navigationController = controller.navigationController as? NavigationController else {
|
guard let self, let controller, let navigationController = controller.navigationController as? NavigationController else {
|
||||||
return
|
return
|
||||||
@ -2864,6 +2848,7 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation
|
|||||||
var hintGroupInCommon: PeerId?
|
var hintGroupInCommon: PeerId?
|
||||||
var forumTopicThread: ChatReplyThreadMessage?
|
var forumTopicThread: ChatReplyThreadMessage?
|
||||||
var isMyProfile = false
|
var isMyProfile = false
|
||||||
|
var switchToGifts = false
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case let .nearbyPeer(distance):
|
case let .nearbyPeer(distance):
|
||||||
@ -2880,10 +2865,13 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation
|
|||||||
forumTopicThread = thread
|
forumTopicThread = thread
|
||||||
case .myProfile:
|
case .myProfile:
|
||||||
isMyProfile = true
|
isMyProfile = true
|
||||||
|
case .myProfileGifts:
|
||||||
|
isMyProfile = true
|
||||||
|
switchToGifts = true
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nearbyPeerDistance, reactionSourceMessageId: reactionSourceMessageId, callMessages: callMessages, isMyProfile: isMyProfile, hintGroupInCommon: hintGroupInCommon, forumTopicThread: forumTopicThread)
|
return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nearbyPeerDistance, reactionSourceMessageId: reactionSourceMessageId, callMessages: callMessages, isMyProfile: isMyProfile, hintGroupInCommon: hintGroupInCommon, forumTopicThread: forumTopicThread, switchToGifts: switchToGifts)
|
||||||
} else if peer is TelegramSecretChat {
|
} else if peer is TelegramSecretChat {
|
||||||
return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: [])
|
return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: [])
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user