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 recommendedChannels
|
||||
case myProfile
|
||||
case myProfileGifts
|
||||
}
|
||||
|
||||
public enum ContactListActionItemInlineIconPosition {
|
||||
@ -975,6 +976,8 @@ public protocol SharedAccountContext: AnyObject {
|
||||
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 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 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
|
||||
|
@ -191,7 +191,7 @@ func _internal_keepCachedStarGiftsUpdated(postbox: Postbox, network: Network) ->
|
||||
|
||||
func managedStarGiftsUpdates(postbox: Postbox, network: Network) -> Signal<Never, NoError> {
|
||||
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> {
|
||||
|
@ -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: {})
|
||||
}
|
||||
)),
|
||||
items: items
|
||||
items: items,
|
||||
isModal: true
|
||||
),
|
||||
environment: {},
|
||||
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):
|
||||
let _ = nameHidden
|
||||
//TODO:localize
|
||||
if !incoming {
|
||||
buttonTitle = ""
|
||||
}
|
||||
let authorName = item.message.author.flatMap { EnginePeer($0) }?.compactDisplayTitle ?? ""
|
||||
title = "Gift from \(authorName)"
|
||||
if let giftText, !giftText.isEmpty {
|
||||
@ -398,7 +401,10 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
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()
|
||||
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)
|
||||
strongSelf.animationNode.frame = animationFrame
|
||||
|
||||
strongSelf.buttonNode.isHidden = buttonTitle.isEmpty
|
||||
strongSelf.buttonTitleNode.isHidden = buttonTitle.isEmpty
|
||||
|
||||
if strongSelf.item == nil {
|
||||
strongSelf.animationNode.started = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
|
@ -162,7 +162,7 @@ private final class SheetPageContent: CombinedComponent {
|
||||
transition: .immediate
|
||||
)
|
||||
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
|
||||
@ -280,7 +280,8 @@ private final class SheetPageContent: CombinedComponent {
|
||||
maximumNumberOfLines: 0
|
||||
)),
|
||||
footer: footer,
|
||||
items: items
|
||||
items: items,
|
||||
isModal: true
|
||||
),
|
||||
environment: {},
|
||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: .greatestFiniteMagnitude),
|
||||
@ -696,12 +697,10 @@ public final class ContentReportScreen: ViewControllerComponentContainer {
|
||||
|
||||
switch result {
|
||||
case .reported:
|
||||
Queue.mainQueue().after(0.1) {
|
||||
completed()
|
||||
}
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
@ -82,7 +82,10 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
super.init()
|
||||
|
||||
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(
|
||||
EngineDataMap(
|
||||
peerIds.map { peerId -> TelegramEngine.EngineData.Item.Peer.Peer in
|
||||
@ -204,10 +207,14 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
descriptionText = "You converted this gift to \(convertStars) Stars. [More About Stars >]()"
|
||||
}
|
||||
} else if let peerId = component.subject.arguments?.peerId, let peer = state.peerMap[peerId] {
|
||||
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 {
|
||||
descriptionText = ""
|
||||
}
|
||||
if let spaceRegex {
|
||||
let nsRange = NSRange(descriptionText.startIndex..., in: descriptionText)
|
||||
let matches = spaceRegex.matches(in: descriptionText, options: [], range: nsRange)
|
||||
@ -273,10 +280,10 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
let tableLinkColor = theme.list.itemAccentColor
|
||||
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(
|
||||
id: "to",
|
||||
title: incoming ? strings.Stars_Transaction_From : strings.Stars_Transaction_To,
|
||||
id: "from",
|
||||
title: strings.Stars_Transaction_From,
|
||||
component: AnyComponent(
|
||||
Button(
|
||||
content: AnyComponent(
|
||||
@ -287,24 +294,24 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
)
|
||||
),
|
||||
action: {
|
||||
if "".isEmpty {
|
||||
component.openPeer(peer)
|
||||
Queue.mainQueue().after(1.0, {
|
||||
component.cancel(false)
|
||||
})
|
||||
} else {
|
||||
// if "".isEmpty {
|
||||
// component.openPeer(peer)
|
||||
// Queue.mainQueue().after(1.0, {
|
||||
// component.cancel(false)
|
||||
// })
|
||||
// } else {
|
||||
if let controller = controller() as? GiftViewScreen, let navigationController = controller.navigationController, let chatController = navigationController.viewControllers.first(where: { $0 is ChatController }) as? ChatController {
|
||||
chatController.playShakeAnimation()
|
||||
}
|
||||
component.cancel(true)
|
||||
}
|
||||
// }
|
||||
}
|
||||
)
|
||||
)
|
||||
))
|
||||
} else {
|
||||
tableItems.append(.init(
|
||||
id: "from",
|
||||
id: "from_anon",
|
||||
title: strings.Stars_Transaction_From,
|
||||
component: AnyComponent(
|
||||
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))
|
||||
)
|
||||
originY += description.size.height + 10.0
|
||||
} else {
|
||||
originY += 11.0
|
||||
}
|
||||
|
||||
let amountSpacing: CGFloat = 1.0
|
||||
@ -439,7 +448,11 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
var amountOrigin = originY
|
||||
if "".isEmpty {
|
||||
amountOrigin -= descriptionSize.height + 10.0
|
||||
if descriptionSize.height > 0 {
|
||||
originY += amount.size.height + 26.0
|
||||
} else {
|
||||
originY += amount.size.height + 2.0
|
||||
}
|
||||
} else {
|
||||
originY += amount.size.height + 20.0
|
||||
}
|
||||
@ -696,14 +709,14 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
case message(EngineMessage)
|
||||
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 {
|
||||
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 {
|
||||
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):
|
||||
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
|
||||
}
|
||||
@ -792,9 +805,25 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
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),
|
||||
elevatedLayout: lastController is ChatController,
|
||||
action: { action in
|
||||
if case .info = action {
|
||||
|
||||
action: { [weak navigationController] action in
|
||||
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
|
||||
}
|
||||
@ -825,6 +854,10 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
self?.dismissAnimated()
|
||||
|
||||
if let navigationController {
|
||||
if let starsContext = context.starsContext {
|
||||
navigationController.pushViewController(context.sharedContext.makeStarsTransactionsScreen(context: context, starsContext: starsContext), animated: true)
|
||||
}
|
||||
|
||||
Queue.mainQueue().after(0.5) {
|
||||
if let lastController = navigationController.viewControllers.last as? ViewController {
|
||||
let resultController = UndoOverlayController(
|
||||
|
@ -41,17 +41,20 @@ public final class ListSectionContentView: UIView {
|
||||
|
||||
public final class Configuration {
|
||||
public let theme: PresentationTheme
|
||||
public let isModal: Bool
|
||||
public let displaySeparators: Bool
|
||||
public let extendsItemHighlightToSection: Bool
|
||||
public let background: ListSectionComponent.Background
|
||||
|
||||
public init(
|
||||
theme: PresentationTheme,
|
||||
isModal: Bool = false,
|
||||
displaySeparators: Bool,
|
||||
extendsItemHighlightToSection: Bool,
|
||||
background: ListSectionComponent.Background
|
||||
) {
|
||||
self.theme = theme
|
||||
self.isModal = isModal
|
||||
self.displaySeparators = displaySeparators
|
||||
self.extendsItemHighlightToSection = extendsItemHighlightToSection
|
||||
self.background = background
|
||||
@ -116,7 +119,7 @@ public final class ListSectionContentView: UIView {
|
||||
backgroundColor = configuration.theme.list.itemHighlightedBackgroundColor
|
||||
} else {
|
||||
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)
|
||||
@ -144,7 +147,7 @@ public final class ListSectionContentView: UIView {
|
||||
if self.highlightedItemId != nil && configuration.extendsItemHighlightToSection {
|
||||
backgroundColor = configuration.theme.list.itemHighlightedBackgroundColor
|
||||
} else {
|
||||
backgroundColor = configuration.theme.list.itemBlocksBackgroundColor
|
||||
backgroundColor = configuration.isModal ? configuration.theme.list.itemModalBlocksBackgroundColor : configuration.theme.list.itemBlocksBackgroundColor
|
||||
}
|
||||
self.externalContentBackgroundView.updateColor(color: backgroundColor, transition: transition)
|
||||
|
||||
@ -305,6 +308,7 @@ public final class ListSectionComponent: Component {
|
||||
public let header: AnyComponent<Empty>?
|
||||
public let footer: AnyComponent<Empty>?
|
||||
public let items: [AnyComponentWithIdentity<Empty>]
|
||||
public let isModal: Bool
|
||||
public let displaySeparators: Bool
|
||||
public let extendsItemHighlightToSection: Bool
|
||||
|
||||
@ -314,6 +318,7 @@ public final class ListSectionComponent: Component {
|
||||
header: AnyComponent<Empty>?,
|
||||
footer: AnyComponent<Empty>?,
|
||||
items: [AnyComponentWithIdentity<Empty>],
|
||||
isModal: Bool = false,
|
||||
displaySeparators: Bool = true,
|
||||
extendsItemHighlightToSection: Bool = false
|
||||
) {
|
||||
@ -322,6 +327,7 @@ public final class ListSectionComponent: Component {
|
||||
self.header = header
|
||||
self.footer = footer
|
||||
self.items = items
|
||||
self.isModal = isModal
|
||||
self.displaySeparators = displaySeparators
|
||||
self.extendsItemHighlightToSection = extendsItemHighlightToSection
|
||||
}
|
||||
@ -342,6 +348,9 @@ public final class ListSectionComponent: Component {
|
||||
if lhs.items != rhs.items {
|
||||
return false
|
||||
}
|
||||
if lhs.isModal != rhs.isModal {
|
||||
return false
|
||||
}
|
||||
if lhs.displaySeparators != rhs.displaySeparators {
|
||||
return false
|
||||
}
|
||||
@ -448,6 +457,7 @@ public final class ListSectionComponent: Component {
|
||||
let contentResult = self.contentView.update(
|
||||
configuration: ListSectionContentView.Configuration(
|
||||
theme: component.theme,
|
||||
isModal: component.isModal,
|
||||
displaySeparators: component.displaySeparators,
|
||||
extendsItemHighlightToSection: component.extendsItemHighlightToSection,
|
||||
background: component.background
|
||||
@ -522,17 +532,20 @@ public final class ListSubSectionComponent: Component {
|
||||
public let theme: PresentationTheme
|
||||
public let leftInset: CGFloat
|
||||
public let items: [AnyComponentWithIdentity<Empty>]
|
||||
public let isModal: Bool
|
||||
public let displaySeparators: Bool
|
||||
|
||||
public init(
|
||||
theme: PresentationTheme,
|
||||
leftInset: CGFloat,
|
||||
items: [AnyComponentWithIdentity<Empty>],
|
||||
isModal: Bool = false,
|
||||
displaySeparators: Bool = true
|
||||
) {
|
||||
self.theme = theme
|
||||
self.leftInset = leftInset
|
||||
self.items = items
|
||||
self.isModal = isModal
|
||||
self.displaySeparators = displaySeparators
|
||||
}
|
||||
|
||||
@ -546,6 +559,9 @@ public final class ListSubSectionComponent: Component {
|
||||
if lhs.items != rhs.items {
|
||||
return false
|
||||
}
|
||||
if lhs.isModal != rhs.isModal {
|
||||
return false
|
||||
}
|
||||
if lhs.displaySeparators != rhs.displaySeparators {
|
||||
return false
|
||||
}
|
||||
@ -615,6 +631,7 @@ public final class ListSubSectionComponent: Component {
|
||||
let contentResult = self.contentView.update(
|
||||
configuration: ListSectionContentView.Configuration(
|
||||
theme: component.theme,
|
||||
isModal: component.isModal,
|
||||
displaySeparators: component.displaySeparators,
|
||||
extendsItemHighlightToSection: false,
|
||||
background: .none(clipped: false)
|
||||
|
@ -8250,9 +8250,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
|
||||
private func openReport(type: PeerInfoReportType, contextController: ContextControllerProtocol?, backAction: ((ContextControllerProtocol) -> Void)?) {
|
||||
guard let controller = self.controller else {
|
||||
return
|
||||
}
|
||||
self.view.endEditing(true)
|
||||
|
||||
switch type {
|
||||
@ -8291,20 +8288,28 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
])
|
||||
self.controller?.present(actionSheet, in: .window(.root))
|
||||
default:
|
||||
let options: [PeerReportOption]
|
||||
if case .user = type {
|
||||
options = [.spam, .fake, .violence, .pornography, .childAbuse]
|
||||
} else {
|
||||
options = [.spam, .fake, .violence, .pornography, .childAbuse, .copyright, .other]
|
||||
}
|
||||
contextController?.dismiss()
|
||||
|
||||
self.context.sharedContext.makeContentReportScreen(context: self.context, subject: .peer(self.peerId), forceDark: false, present: { [weak self] controller in
|
||||
self?.controller?.push(controller)
|
||||
}, completion: {
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 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.controller?.present(peerReportOptionsController(context: strongSelf.context, subject: .messages(Array(messageIds).sorted()), passthrough: false, present: { c, a in
|
||||
self?.controller?.present(c, in: .window(.root), with: a)
|
||||
}, push: { c in
|
||||
self?.controller?.push(c)
|
||||
}, completion: { _, _ in }), in: .window(.root))
|
||||
|
||||
|
||||
strongSelf.context.sharedContext.makeContentReportScreen(context: strongSelf.context, subject: .messages(Array(messageIds).sorted()), forceDark: false, present: { [weak self] controller in
|
||||
self?.controller?.push(controller)
|
||||
}, completion: {})
|
||||
}, displayCopyProtectionTip: { [weak self] node, save in
|
||||
if let strongSelf = self, let peer = strongSelf.data?.peer, let messageIds = strongSelf.state.selectedMessageIds, !messageIds.isEmpty {
|
||||
let _ = (strongSelf.context.engine.data.get(EngineDataMap(
|
||||
@ -12284,6 +12285,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
private weak var requestsContext: PeerInvitationImportersContext?
|
||||
fileprivate let starsContext: StarsContext?
|
||||
private let switchToRecommendedChannels: Bool
|
||||
private let switchToGifts: Bool
|
||||
private let chatLocation: ChatLocation
|
||||
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)?
|
||||
|
||||
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.updatedPresentationData = updatedPresentationData
|
||||
self.peerId = peerId
|
||||
@ -12354,6 +12356,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
self.hintGroupInCommon = hintGroupInCommon
|
||||
self.requestsContext = requestsContext
|
||||
self.switchToRecommendedChannels = switchToRecommendedChannels
|
||||
self.switchToGifts = switchToGifts
|
||||
|
||||
if let forumTopicThread = forumTopicThread {
|
||||
self.chatLocation = .replyThread(message: forumTopicThread)
|
||||
@ -12694,7 +12697,13 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
}
|
||||
|
||||
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.activeSessionsContextAndCount.set(self.activeSessionsContextAndCount.get())
|
||||
self.cachedDataPromise.set(self.controllerNode.cachedDataPromise.get())
|
||||
|
@ -87,6 +87,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let isFirstTime = starsProducts == nil
|
||||
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.starsProducts = state.gifts
|
||||
@ -96,7 +97,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
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) {
|
||||
self.updateScrolling()
|
||||
self.updateScrolling(transition: .immediate)
|
||||
}
|
||||
|
||||
func updateScrolling() {
|
||||
func updateScrolling(transition: ComponentTransition) {
|
||||
if let starsProducts = self.starsProducts, let params = self.currentParams {
|
||||
let optionSpacing: CGFloat = 10.0
|
||||
let sideInset = params.sideInset + 16.0
|
||||
@ -140,13 +141,14 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
let itemId = AnyHashable(product.date)
|
||||
validIds.append(itemId)
|
||||
|
||||
let itemTransition = ComponentTransition.immediate
|
||||
var itemTransition = transition
|
||||
let visibleItem: ComponentView<Empty>
|
||||
if let current = self.starsItems[itemId] {
|
||||
visibleItem = current
|
||||
} else {
|
||||
visibleItem = ComponentView()
|
||||
self.starsItems[itemId] = visibleItem
|
||||
itemTransition = .immediate
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
if self.peerId == self.context.account.peerId {
|
||||
@ -354,7 +376,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
}
|
||||
self.scrollNode.view.isScrollEnabled = !isScrollingLockedAtTop
|
||||
|
||||
self.updateScrolling()
|
||||
self.updateScrolling(transition: ComponentTransition(transition))
|
||||
}
|
||||
|
||||
public func findLoadedMessage(id: MessageId) -> Message? {
|
||||
|
@ -1037,7 +1037,7 @@ public final class StarsTransactionsScreen: ViewControllerComponentContainer {
|
||||
guard let self else {
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
@ -741,6 +741,9 @@ public final class TextFieldComponent: Component {
|
||||
}
|
||||
|
||||
self.insertText(NSAttributedString(string: insertString))
|
||||
} else if (range.length == 0 && text == "\n"), let returnKeyAction = component.returnKeyAction {
|
||||
returnKeyAction()
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
@ -2247,13 +2316,9 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
var sendMessageImpl: ((EnginePeer) -> Void)?
|
||||
|
||||
//TODO:localize
|
||||
let controller: ViewController
|
||||
// if case .stars = source {
|
||||
// let options = Promise<[StarsGiftOption]>()
|
||||
// options.set(context.engine.payments.starsGiftOptions(peerId: nil))
|
||||
let options = Promise<[PremiumGiftCodeOption]>()
|
||||
options.set(context.engine.payments.premiumGiftCodeOptions(peerId: nil))
|
||||
let contactsController = context.sharedContext.makeContactSelectionController(ContactSelectionControllerParams(
|
||||
let controller = context.sharedContext.makeContactSelectionController(ContactSelectionControllerParams(
|
||||
context: context,
|
||||
mode: starsMode,
|
||||
autoDismiss: false,
|
||||
@ -2267,12 +2332,12 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
}
|
||||
))
|
||||
let _ = combineLatest(queue: Queue.mainQueue(), contactsController.result, options.get())
|
||||
.startStandalone(next: { [weak contactsController] result, options in
|
||||
.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 giftController = GiftOptionsScreen(context: context, starsContext: starsContext, peerId: peer.id, premiumOptions: premiumOptions)
|
||||
giftController.navigationPresentation = .modal
|
||||
contactsController?.push(giftController)
|
||||
controller?.push(giftController)
|
||||
|
||||
// completion?([peer.id])
|
||||
|
||||
@ -2281,87 +2346,6 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
}
|
||||
}
|
||||
})
|
||||
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
|
||||
guard let self, let controller, let navigationController = controller.navigationController as? NavigationController else {
|
||||
@ -2864,6 +2848,7 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation
|
||||
var hintGroupInCommon: PeerId?
|
||||
var forumTopicThread: ChatReplyThreadMessage?
|
||||
var isMyProfile = false
|
||||
var switchToGifts = false
|
||||
|
||||
switch mode {
|
||||
case let .nearbyPeer(distance):
|
||||
@ -2880,10 +2865,13 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation
|
||||
forumTopicThread = thread
|
||||
case .myProfile:
|
||||
isMyProfile = true
|
||||
case .myProfileGifts:
|
||||
isMyProfile = true
|
||||
switchToGifts = true
|
||||
default:
|
||||
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 {
|
||||
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