mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Phone numbers improvements
This commit is contained in:
parent
55c38c8590
commit
6de753b14a
@ -12190,3 +12190,19 @@ Sorry for the inconvenience.";
|
||||
|
||||
"EmojiPacks.UnarchiveEmojiPacksConfirmation_1" = "Unarchive %@ Pack";
|
||||
"EmojiPacks.UnarchiveEmojiPacksConfirmation_any" = "Unarchive %@ Packs";
|
||||
|
||||
"HashtagSearch.ThisChat" = "This Chat";
|
||||
"HashtagSearch.MyMessages" = "My Messages";
|
||||
"HashtagSearch.PublicPosts" = "Public Posts";
|
||||
|
||||
"Chat.Context.Phone.AddToContacts" = "Add to Contacts";
|
||||
"Chat.Context.Phone.CreateNewContact" = "Create New Contact";
|
||||
"Chat.Context.Phone.AddToExistingContact" = "Add to Existing Contact";
|
||||
"Chat.Context.Phone.SendMessage" = "Send Message";
|
||||
"Chat.Context.Phone.TelegramVoiceCall" = "Telegram Voice Call";
|
||||
"Chat.Context.Phone.TelegramVideoCall" = "Telegram Video Call";
|
||||
"Chat.Context.Phone.InviteToTelegram" = "Invite to Telegram";
|
||||
"Chat.Context.Phone.CallViaCarrier" = "Call via Carrier";
|
||||
"Chat.Context.Phone.CopyNumber" = "Copy Number";
|
||||
"Chat.Context.Phone.NotOnTelegram" = "This number is not on Telegram.";
|
||||
"Chat.Context.Phone.ViewProfile" = "View Profile";
|
||||
|
@ -932,7 +932,7 @@ public protocol SharedAccountContext: AnyObject {
|
||||
func makeOverlayAudioPlayerController(context: AccountContext, chatLocation: ChatLocation, type: MediaManagerPlayerType, initialMessageId: MessageId, initialOrder: MusicPlaybackSettingsOrder, playlistLocation: SharedMediaPlaylistLocation?, parentNavigationController: NavigationController?) -> ViewController & OverlayAudioPlayerController
|
||||
func makePeerInfoController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool, fromChat: Bool, requestsContext: PeerInvitationImportersContext?) -> ViewController?
|
||||
func makeChannelAdminController(context: AccountContext, peerId: PeerId, adminId: PeerId, initialParticipant: ChannelParticipant) -> ViewController?
|
||||
func makeDeviceContactInfoController(context: AccountContext, subject: DeviceContactInfoSubject, completed: (() -> Void)?, cancelled: (() -> Void)?) -> ViewController
|
||||
func makeDeviceContactInfoController(context: ShareControllerAccountContext, environment: ShareControllerEnvironment, subject: DeviceContactInfoSubject, completed: (() -> Void)?, cancelled: (() -> Void)?) -> ViewController
|
||||
func makePeersNearbyController(context: AccountContext) -> ViewController
|
||||
func makeComposeController(context: AccountContext) -> ViewController
|
||||
func makeChatListController(context: AccountContext, location: ChatListControllerLocation, controlsHistoryPreload: Bool, hideNetworkActivityStatus: Bool, previewing: Bool, enableDebugActions: Bool) -> ChatListController
|
||||
@ -1224,3 +1224,28 @@ public struct StickersSearchConfiguration {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public protocol ShareControllerAccountContext: AnyObject {
|
||||
var accountId: AccountRecordId { get }
|
||||
var accountPeerId: EnginePeer.Id { get }
|
||||
var stateManager: AccountStateManager { get }
|
||||
var engineData: TelegramEngine.EngineData { get }
|
||||
var animationCache: AnimationCache { get }
|
||||
var animationRenderer: MultiAnimationRenderer { get }
|
||||
var contentSettings: ContentSettings { get }
|
||||
var appConfiguration: AppConfiguration { get }
|
||||
|
||||
func resolveInlineStickers(fileIds: [Int64]) -> Signal<[Int64: TelegramMediaFile], NoError>
|
||||
}
|
||||
|
||||
public protocol ShareControllerEnvironment: AnyObject {
|
||||
var presentationData: PresentationData { get }
|
||||
var updatedPresentationData: Signal<PresentationData, NoError> { get }
|
||||
var isMainApp: Bool { get }
|
||||
var energyUsageSettings: EnergyUsageSettings { get }
|
||||
|
||||
var mediaManager: MediaManager? { get }
|
||||
|
||||
func setAccountUserInterfaceInUse(id: AccountRecordId) -> Disposable
|
||||
func donateSendMessageIntent(account: ShareControllerAccountContext, peerIds: [EnginePeer.Id])
|
||||
}
|
||||
|
@ -971,6 +971,7 @@ public protocol ChatController: ViewController {
|
||||
var chatLocation: ChatLocation { get }
|
||||
var canReadHistory: ValuePromise<Bool> { get }
|
||||
var parentController: ViewController? { get set }
|
||||
var customNavigationController: NavigationController? { get set }
|
||||
|
||||
var purposefulAction: (() -> Void)? { get set }
|
||||
|
||||
|
@ -28,13 +28,22 @@ public final class BotCheckoutController: ViewController {
|
||||
}
|
||||
|
||||
public static func fetch(context: AccountContext, source: BotPaymentInvoiceSource) -> Signal<InputData, FetchError> {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let theme = context.sharedContext.currentPresentationData.with { $0 }.theme
|
||||
let themeParams: [String: Any] = [
|
||||
"bg_color": Int32(bitPattern: presentationData.theme.list.plainBackgroundColor.argb),
|
||||
"text_color": Int32(bitPattern: presentationData.theme.list.itemPrimaryTextColor.argb),
|
||||
"link_color": Int32(bitPattern: presentationData.theme.list.itemAccentColor.argb),
|
||||
"button_color": Int32(bitPattern: presentationData.theme.list.itemCheckColors.fillColor.argb),
|
||||
"button_text_color": Int32(bitPattern: presentationData.theme.list.itemCheckColors.foregroundColor.argb)
|
||||
"bg_color": Int32(bitPattern: theme.list.plainBackgroundColor.rgb),
|
||||
"secondary_bg_color": Int32(bitPattern: theme.list.blocksBackgroundColor.rgb),
|
||||
"text_color": Int32(bitPattern: theme.list.itemPrimaryTextColor.rgb),
|
||||
"hint_color": Int32(bitPattern: theme.list.itemSecondaryTextColor.rgb),
|
||||
"link_color": Int32(bitPattern: theme.list.itemAccentColor.rgb),
|
||||
"button_color": Int32(bitPattern: theme.list.itemCheckColors.fillColor.rgb),
|
||||
"button_text_color": Int32(bitPattern: theme.list.itemCheckColors.foregroundColor.rgb),
|
||||
"header_bg_color": Int32(bitPattern: theme.rootController.navigationBar.opaqueBackgroundColor.rgb),
|
||||
"accent_text_color": Int32(bitPattern: theme.list.itemAccentColor.rgb),
|
||||
"section_bg_color": Int32(bitPattern: theme.list.itemBlocksBackgroundColor.rgb),
|
||||
"section_header_text_color": Int32(bitPattern: theme.list.freeTextColor.rgb),
|
||||
"subtitle_text_color": Int32(bitPattern: theme.list.itemSecondaryTextColor.rgb),
|
||||
"destructive_text_color": Int32(bitPattern: theme.list.itemDestructiveColor.rgb),
|
||||
"section_separator_color": Int32(bitPattern: theme.list.itemBlocksSeparatorColor.rgb)
|
||||
]
|
||||
|
||||
return context.engine.payments.fetchBotPaymentForm(source: source, themeParams: themeParams)
|
||||
|
@ -23,6 +23,7 @@ import StoryContainerScreen
|
||||
import ChatListHeaderComponent
|
||||
import TelegramIntents
|
||||
import UndoUI
|
||||
import ShareController
|
||||
|
||||
private final class HeaderContextReferenceContentSource: ContextReferenceContentSource {
|
||||
private let controller: ViewController
|
||||
@ -309,7 +310,7 @@ public class ContactsController: ViewController {
|
||||
guard let strongSelf = self, let value = value else {
|
||||
return
|
||||
}
|
||||
(strongSelf.navigationController as? NavigationController)?.pushViewController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .vcard(nil, id, value), completed: nil, cancelled: nil), completion: { [weak self] in
|
||||
(strongSelf.navigationController as? NavigationController)?.pushViewController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: strongSelf.context), environment: ShareControllerAppEnvironment(sharedContext: strongSelf.context.sharedContext), subject: .vcard(nil, id, value), completed: nil, cancelled: nil), completion: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.contactsNode.contactListNode.listNode.clearHighlightAnimated(true)
|
||||
}
|
||||
@ -741,7 +742,7 @@ public class ContactsController: ViewController {
|
||||
case .allowed:
|
||||
let contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: "", lastName: "", phoneNumbers: [DeviceContactPhoneNumberData(label: "_$!<Mobile>!$_", value: "+")]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "")
|
||||
if let navigationController = strongSelf.context.sharedContext.mainWindow?.viewController as? NavigationController {
|
||||
navigationController.pushViewController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .create(peer: nil, contactData: contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in
|
||||
navigationController.pushViewController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: strongSelf.context), environment: ShareControllerAppEnvironment(sharedContext: strongSelf.context.sharedContext), subject: .create(peer: nil, contactData: contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -755,7 +756,7 @@ public class ContactsController: ViewController {
|
||||
}
|
||||
} else {
|
||||
if let navigationController = strongSelf.context.sharedContext.mainWindow?.viewController as? NavigationController {
|
||||
navigationController.pushViewController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .vcard(nil, stableId, contactData), completed: nil, cancelled: nil))
|
||||
navigationController.pushViewController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: strongSelf.context), environment: ShareControllerAppEnvironment(sharedContext: strongSelf.context.sharedContext), subject: .vcard(nil, stableId, contactData), completed: nil, cancelled: nil))
|
||||
}
|
||||
}
|
||||
}), completed: nil, cancelled: nil))
|
||||
|
@ -121,6 +121,19 @@ public final class ContextActionNode: ASDisplayNode, ContextActionNodeProtocol {
|
||||
statusNode.attributedText = NSAttributedString(string: value, font: subtitleFont, textColor: presentationData.theme.contextMenu.secondaryColor)
|
||||
statusNode.maximumNumberOfLines = 1
|
||||
self.statusNode = statusNode
|
||||
case let .secondLineWithAttributedValue(value):
|
||||
self.textNode.maximumNumberOfLines = 1
|
||||
let statusNode = ImmediateTextNode()
|
||||
statusNode.isAccessibilityElement = false
|
||||
statusNode.isUserInteractionEnabled = false
|
||||
statusNode.displaysAsynchronously = false
|
||||
|
||||
let mutableString = value.mutableCopy() as! NSMutableAttributedString
|
||||
mutableString.addAttribute(.foregroundColor, value: presentationData.theme.contextMenu.secondaryColor, range: NSRange(location: 0, length: mutableString.length))
|
||||
mutableString.addAttribute(.font, value: subtitleFont, range: NSRange(location: 0, length: mutableString.length))
|
||||
statusNode.attributedText = mutableString
|
||||
statusNode.maximumNumberOfLines = 1
|
||||
self.statusNode = statusNode
|
||||
case .multiline:
|
||||
self.textNode.maximumNumberOfLines = 0
|
||||
self.statusNode = nil
|
||||
@ -350,10 +363,15 @@ public final class ContextActionNode: ASDisplayNode, ContextActionNodeProtocol {
|
||||
|
||||
self.textNode.attributedText = NSAttributedString(string: self.action.text, font: titleFont, textColor: textColor)
|
||||
|
||||
let subtitleFont = Font.regular(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0)
|
||||
switch self.action.textLayout {
|
||||
case let .secondLineWithValue(value):
|
||||
let subtitleFont = Font.regular(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0)
|
||||
self.statusNode?.attributedText = NSAttributedString(string: value, font: subtitleFont, textColor: presentationData.theme.contextMenu.secondaryColor)
|
||||
case let .secondLineWithAttributedValue(value):
|
||||
let mutableString = value.mutableCopy() as! NSMutableAttributedString
|
||||
mutableString.addAttribute(.foregroundColor, value: presentationData.theme.contextMenu.secondaryColor, range: NSRange(location: 0, length: mutableString.length))
|
||||
mutableString.addAttribute(.font, value: subtitleFont, range: NSRange(location: 0, length: mutableString.length))
|
||||
self.statusNode?.attributedText = mutableString
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ public enum ContextMenuActionItemTextLayout {
|
||||
case singleLine
|
||||
case twoLinesMax
|
||||
case secondLineWithValue(String)
|
||||
case secondLineWithAttributedValue(NSAttributedString)
|
||||
case multiline
|
||||
}
|
||||
|
||||
@ -2150,6 +2151,7 @@ public protocol ContextExtractedContentSource: AnyObject {
|
||||
var initialAppearanceOffset: CGPoint { get }
|
||||
var centerVertically: Bool { get }
|
||||
var keepInPlace: Bool { get }
|
||||
var adjustContentHorizontally: Bool { get }
|
||||
var adjustContentForSideInset: Bool { get }
|
||||
var ignoreContentTouches: Bool { get }
|
||||
var blurBackground: Bool { get }
|
||||
@ -2170,6 +2172,10 @@ public extension ContextExtractedContentSource {
|
||||
return false
|
||||
}
|
||||
|
||||
var adjustContentHorizontally: Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
var adjustContentForSideInset: Bool {
|
||||
return false
|
||||
}
|
||||
|
@ -228,21 +228,7 @@ public final class ContextControllerActionsListActionItemNode: HighlightTracking
|
||||
let iconSpacing: CGFloat = 8.0
|
||||
|
||||
self.highlightBackgroundNode.backgroundColor = presentationData.theme.contextMenu.itemHighlightedBackgroundColor
|
||||
|
||||
var subtitle: String?
|
||||
switch self.item.textLayout {
|
||||
case .singleLine:
|
||||
self.titleLabelNode.maximumNumberOfLines = 1
|
||||
case .twoLinesMax:
|
||||
self.titleLabelNode.maximumNumberOfLines = 2
|
||||
case let .secondLineWithValue(subtitleValue):
|
||||
self.titleLabelNode.maximumNumberOfLines = 1
|
||||
subtitle = subtitleValue
|
||||
case .multiline:
|
||||
self.titleLabelNode.maximumNumberOfLines = 0
|
||||
self.titleLabelNode.lineSpacing = 0.1
|
||||
}
|
||||
|
||||
|
||||
var forcedHeight: CGFloat?
|
||||
var titleVerticalOffset: CGFloat?
|
||||
let titleFont: UIFont
|
||||
@ -265,6 +251,30 @@ public final class ContextControllerActionsListActionItemNode: HighlightTracking
|
||||
let subtitleFont = Font.regular(presentationData.listsFontSize.baseDisplaySize * 14.0 / 17.0)
|
||||
let subtitleColor = presentationData.theme.contextMenu.secondaryColor
|
||||
|
||||
var subtitle: NSAttributedString?
|
||||
switch self.item.textLayout {
|
||||
case .singleLine:
|
||||
self.titleLabelNode.maximumNumberOfLines = 1
|
||||
case .twoLinesMax:
|
||||
self.titleLabelNode.maximumNumberOfLines = 2
|
||||
case let .secondLineWithValue(subtitleValue):
|
||||
self.titleLabelNode.maximumNumberOfLines = 1
|
||||
subtitle = NSAttributedString(
|
||||
string: subtitleValue,
|
||||
font: subtitleFont,
|
||||
textColor: subtitleColor
|
||||
)
|
||||
case let .secondLineWithAttributedValue(subtitleValue):
|
||||
self.titleLabelNode.maximumNumberOfLines = 1
|
||||
let mutableString = subtitleValue.mutableCopy() as! NSMutableAttributedString
|
||||
mutableString.addAttribute(.foregroundColor, value: subtitleColor, range: NSRange(location: 0, length: mutableString.length))
|
||||
mutableString.addAttribute(.font, value: subtitleFont, range: NSRange(location: 0, length: mutableString.length))
|
||||
subtitle = mutableString
|
||||
case .multiline:
|
||||
self.titleLabelNode.maximumNumberOfLines = 0
|
||||
self.titleLabelNode.lineSpacing = 0.1
|
||||
}
|
||||
|
||||
let titleColor: UIColor
|
||||
switch self.item.textColor {
|
||||
case .primary:
|
||||
@ -308,13 +318,7 @@ public final class ContextControllerActionsListActionItemNode: HighlightTracking
|
||||
|
||||
self.titleLabelNode.isUserInteractionEnabled = self.titleLabelNode.tapAttributeAction != nil && self.item.action == nil
|
||||
|
||||
self.subtitleNode.attributedText = subtitle.flatMap { subtitle in
|
||||
return NSAttributedString(
|
||||
string: subtitle,
|
||||
font: subtitleFont,
|
||||
textColor: subtitleColor
|
||||
)
|
||||
}
|
||||
self.subtitleNode.attributedText = subtitle
|
||||
|
||||
var iconSize: CGSize?
|
||||
if let iconSource = self.item.iconSource {
|
||||
|
@ -1064,6 +1064,9 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
||||
if let contentNode = itemContentNode {
|
||||
var contentFrame = CGRect(origin: CGPoint(x: contentParentGlobalFrame.minX + contentRect.minX - contentNode.containingItem.contentRect.minX, y: contentRect.minY - contentNode.containingItem.contentRect.minY + contentVerticalOffset + additionalVisibleOffsetY), size: contentNode.containingItem.view.bounds.size)
|
||||
if case let .extracted(extracted) = self.source {
|
||||
if extracted.adjustContentHorizontally {
|
||||
contentFrame.origin.x = combinedActionsFrame.minX
|
||||
}
|
||||
if extracted.centerVertically {
|
||||
if combinedActionsFrame.height.isZero {
|
||||
contentFrame.origin.y = floorToScreenPixels((layout.size.height - contentFrame.height) / 2.0)
|
||||
@ -1160,7 +1163,10 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
||||
let contentX = contentParentGlobalFrame.minX + contentRect.minX - contentNode.containingItem.contentRect.minX
|
||||
let contentWidth = contentNode.containingItem.view.bounds.size.width
|
||||
let contentHeight = contentNode.containingItem.view.bounds.size.height
|
||||
if case let .extracted(extracted) = self.source, extracted.centerVertically {
|
||||
if case let .extracted(extracted) = self.source, extracted.adjustContentHorizontally {
|
||||
let fixedContentX = self.actionsContainerNode.frame.minX
|
||||
animationInContentXDistance = fixedContentX - contentX
|
||||
} else if case let .extracted(extracted) = self.source, extracted.centerVertically {
|
||||
if actionsSize.height.isZero {
|
||||
var initialContentRect = contentRect
|
||||
initialContentRect.origin.y += extracted.initialAppearanceOffset.y
|
||||
@ -1429,7 +1435,10 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
||||
var animationInContentXDistance: CGFloat = 0.0
|
||||
let contentX = contentParentGlobalFrame.minX + contentRect.minX - contentNode.containingItem.contentRect.minX
|
||||
let contentWidth = contentNode.containingItem.view.bounds.size.width
|
||||
if case let .extracted(extracted) = self.source, extracted.centerVertically {
|
||||
if case let .extracted(extracted) = self.source, extracted.adjustContentHorizontally {
|
||||
let fixedContentX = self.actionsContainerNode.frame.minX
|
||||
animationInContentXDistance = contentX - fixedContentX
|
||||
} else if case let .extracted(extracted) = self.source, extracted.centerVertically {
|
||||
if actionsSize.height.isZero {
|
||||
// let fixedContentY = floorToScreenPixels((layout.size.height - contentHeight) / 2.0)
|
||||
animationInContentYDistance = 0.0 //contentY - fixedContentY
|
||||
|
@ -330,7 +330,7 @@ public func generateTintedImage(image: UIImage?, color: UIColor, backgroundColor
|
||||
return tintedImage
|
||||
}
|
||||
|
||||
public func generateGradientTintedImage(image: UIImage?, colors: [UIColor]) -> UIImage? {
|
||||
public func generateGradientTintedImage(image: UIImage?, colors: [UIColor], direction: GradientImageDirection = .vertical) -> UIImage? {
|
||||
guard let image = image else {
|
||||
return nil
|
||||
}
|
||||
@ -357,7 +357,21 @@ public func generateGradientTintedImage(image: UIImage?, colors: [UIColor]) -> U
|
||||
let colorSpace = DeviceGraphicsContextSettings.shared.colorSpace
|
||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
|
||||
|
||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: imageRect.height), end: CGPoint(x: 0.0, y: 0.0), options: CGGradientDrawingOptions())
|
||||
let start: CGPoint
|
||||
let end: CGPoint
|
||||
switch direction {
|
||||
case .horizontal:
|
||||
start = .zero
|
||||
end = CGPoint(x: imageRect.width, y: 0.0)
|
||||
case .vertical:
|
||||
start = CGPoint(x: 0.0, y: imageRect.height)
|
||||
end = .zero
|
||||
case .diagonal:
|
||||
start = CGPoint(x: 0.0, y: 0.0)
|
||||
end = CGPoint(x: imageRect.width, y: imageRect.height)
|
||||
}
|
||||
|
||||
context.drawLinearGradient(gradient, start: start, end: end, options: CGGradientDrawingOptions())
|
||||
} else if !colors.isEmpty {
|
||||
context.setFillColor(colors[0].cgColor)
|
||||
context.fill(imageRect)
|
||||
|
@ -1327,8 +1327,6 @@ private extension UIBezierPath {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
extension UIImageView {
|
||||
func setDrawingAnimatedImage(data: Data) {
|
||||
DispatchQueue.global().async {
|
||||
@ -1354,48 +1352,3 @@ extension UIImageView {
|
||||
self.animationRepeatCount = 0
|
||||
}
|
||||
}
|
||||
|
||||
//private func prerenderEntityTransformations(entity: DrawingEntity, image: UIImage, colorSpace: CGColorSpace) -> UIImage {
|
||||
// let imageSize = image.size
|
||||
//
|
||||
// let angle: CGFloat
|
||||
// var scale: CGFloat
|
||||
// let position: CGPoint
|
||||
//
|
||||
// if let entity = entity as? DrawingStickerEntity {
|
||||
// angle = -entity.rotation
|
||||
// scale = entity.scale
|
||||
// position = entity.position
|
||||
// } else {
|
||||
// fatalError()
|
||||
// }
|
||||
//
|
||||
// let rotatedSize = CGSize(
|
||||
// width: abs(imageSize.width * cos(angle)) + abs(imageSize.height * sin(angle)),
|
||||
// height: abs(imageSize.width * sin(angle)) + abs(imageSize.height * cos(angle))
|
||||
// )
|
||||
// let newSize = CGSize(width: rotatedSize.width * scale, height: rotatedSize.height * scale)
|
||||
//
|
||||
// let newImage = generateImage(newSize, contextGenerator: { size, context in
|
||||
// context.setAllowsAntialiasing(true)
|
||||
// context.setShouldAntialias(true)
|
||||
// context.interpolationQuality = .high
|
||||
// context.clear(CGRect(origin: .zero, size: size))
|
||||
// context.translateBy(x: newSize.width * 0.5, y: newSize.height * 0.5)
|
||||
// context.rotate(by: angle)
|
||||
// context.scaleBy(x: scale, y: scale)
|
||||
// let drawRect = CGRect(
|
||||
// x: -imageSize.width * 0.5,
|
||||
// y: -imageSize.height * 0.5,
|
||||
// width: imageSize.width,
|
||||
// height: imageSize.height
|
||||
// )
|
||||
// if let cgImage = image.cgImage {
|
||||
// context.draw(cgImage, in: drawRect)
|
||||
// }
|
||||
// }, scale: 1.0)!
|
||||
//
|
||||
// let _ = position
|
||||
//
|
||||
// return newImage
|
||||
//}
|
||||
|
@ -1995,7 +1995,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, ASS
|
||||
let changeEmailActionButtonFrame: CGRect
|
||||
let resendCodeActionFrame: CGRect
|
||||
let resendCodeActionButtonFrame: CGRect
|
||||
if changeEmailActionSize.width + resendCodeActionSize.width > layout.size.width - buttonFrame.minX * 2.0 {
|
||||
if changeEmailActionSize.width + resendCodeActionSize.width > layout.size.width - buttonFrame.minX * 2.0 - 32.0 {
|
||||
changeEmailActionButtonFrame = CGRect(origin: CGPoint(x: buttonFrame.minX, y: buttonFrame.minY), size: CGSize(width: buttonFrame.width, height: buttonFrame.height))
|
||||
changeEmailActionFrame = CGRect(origin: CGPoint(x: changeEmailActionButtonFrame.minX + floor((changeEmailActionButtonFrame.width - changeEmailActionSize.width) / 2.0), y: changeEmailActionButtonFrame.minY + floor((changeEmailActionButtonFrame.height - changeEmailActionSize.height) / 2.0)), size: changeEmailActionSize)
|
||||
resendCodeActionButtonFrame = CGRect(origin: CGPoint(x: buttonFrame.minX, y: buttonFrame.maxY), size: CGSize(width: buttonFrame.width, height: buttonFrame.height))
|
||||
|
@ -24,6 +24,8 @@ import UndoUI
|
||||
import GalleryUI
|
||||
import PeerAvatarGalleryUI
|
||||
import Postbox
|
||||
import ShareController
|
||||
import ContextUI
|
||||
|
||||
private enum DeviceContactInfoAction {
|
||||
case sendMessage
|
||||
@ -33,7 +35,7 @@ private enum DeviceContactInfoAction {
|
||||
}
|
||||
|
||||
private final class DeviceContactInfoControllerArguments {
|
||||
let context: AccountContext
|
||||
let accountContext: AccountContext?
|
||||
let isPlain: Bool
|
||||
let updateEditingName: (ItemListAvatarAndNameInfoItemName) -> Void
|
||||
let updatePhone: (Int64, String) -> Void
|
||||
@ -50,8 +52,8 @@ private final class DeviceContactInfoControllerArguments {
|
||||
let updateShareViaException: (Bool) -> Void
|
||||
let openAvatar: (EnginePeer) -> Void
|
||||
|
||||
init(context: AccountContext, isPlain: Bool, updateEditingName: @escaping (ItemListAvatarAndNameInfoItemName) -> Void, updatePhone: @escaping (Int64, String) -> Void, updatePhoneLabel: @escaping (Int64, String) -> Void, deletePhone: @escaping (Int64) -> Void, setPhoneIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, addPhoneNumber: @escaping () -> Void, performAction: @escaping (DeviceContactInfoAction) -> Void, toggleSelection: @escaping (DeviceContactInfoDataId) -> Void, callPhone: @escaping (String) -> Void, openUrl: @escaping (String) -> Void, openAddress: @escaping (DeviceContactAddressData) -> Void, displayCopyContextMenu: @escaping (DeviceContactInfoEntryTag, String) -> Void, updateShareViaException: @escaping (Bool) -> Void, openAvatar: @escaping (EnginePeer) -> Void) {
|
||||
self.context = context
|
||||
init(accountContext: AccountContext?, isPlain: Bool, updateEditingName: @escaping (ItemListAvatarAndNameInfoItemName) -> Void, updatePhone: @escaping (Int64, String) -> Void, updatePhoneLabel: @escaping (Int64, String) -> Void, deletePhone: @escaping (Int64) -> Void, setPhoneIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, addPhoneNumber: @escaping () -> Void, performAction: @escaping (DeviceContactInfoAction) -> Void, toggleSelection: @escaping (DeviceContactInfoDataId) -> Void, callPhone: @escaping (String) -> Void, openUrl: @escaping (String) -> Void, openAddress: @escaping (DeviceContactAddressData) -> Void, displayCopyContextMenu: @escaping (DeviceContactInfoEntryTag, String) -> Void, updateShareViaException: @escaping (Bool) -> Void, openAvatar: @escaping (EnginePeer) -> Void) {
|
||||
self.accountContext = accountContext
|
||||
self.isPlain = isPlain
|
||||
self.updateEditingName = updateEditingName
|
||||
self.updatePhone = updatePhone
|
||||
@ -404,7 +406,10 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry {
|
||||
let arguments = arguments as! DeviceContactInfoControllerArguments
|
||||
switch self {
|
||||
case let .info(_, _, _, dateTimeFormat, peer, state, jobSummary, _, hiddenAvatar):
|
||||
return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .contact, peer: peer, presence: nil, label: jobSummary, memberCount: nil, state: state, sectionId: self.section, style: arguments.isPlain ? .plain : .blocks(withTopInset: false, withExtendedBottomInset: true), editingNameUpdated: { editingName in
|
||||
guard let accountContext = arguments.accountContext else {
|
||||
fatalError()
|
||||
}
|
||||
return ItemListAvatarAndNameInfoItem(accountContext: accountContext, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .contact, peer: peer, presence: nil, label: jobSummary, memberCount: nil, state: state, sectionId: self.section, style: arguments.isPlain ? .plain : .blocks(withTopInset: false, withExtendedBottomInset: true), editingNameUpdated: { editingName in
|
||||
arguments.updateEditingName(editingName)
|
||||
}, avatarTapped: {
|
||||
if peer.smallProfileImage != nil {
|
||||
@ -625,7 +630,7 @@ private func filteredContactData(contactData: DeviceContactExtendedData, exclude
|
||||
return DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: contactData.basicData.firstName, lastName: contactData.basicData.lastName, phoneNumbers: phoneNumbers), middleName: contactData.middleName, prefix: contactData.prefix, suffix: contactData.suffix, organization: includeJob ? contactData.organization : "", jobTitle: includeJob ? contactData.jobTitle : "", department: includeJob ? contactData.department : "", emailAddresses: emailAddresses, urls: urls, addresses: addresses, birthdayDate: includeBirthday ? contactData.birthdayDate : nil, socialProfiles: socialProfiles, instantMessagingProfiles: instantMessagingProfiles, note: includeNote ? contactData.note : "")
|
||||
}
|
||||
|
||||
private func deviceContactInfoEntries(account: Account, engine: TelegramEngine, presentationData: PresentationData, peer: EnginePeer?, isShare: Bool, shareViaException: Bool, contactData: DeviceContactExtendedData, isContact: Bool, state: DeviceContactInfoState, selecting: Bool, editingPhoneNumbers: Bool, hiddenAvatar: TelegramMediaImageRepresentation?) -> [DeviceContactInfoEntry] {
|
||||
private func deviceContactInfoEntries(context: ShareControllerAccountContext, presentationData: PresentationData, peer: EnginePeer?, isShare: Bool, shareViaException: Bool, contactData: DeviceContactExtendedData, isContact: Bool, state: DeviceContactInfoState, selecting: Bool, editingPhoneNumbers: Bool, hiddenAvatar: TelegramMediaImageRepresentation?) -> [DeviceContactInfoEntry] {
|
||||
var entries: [DeviceContactInfoEntry] = []
|
||||
|
||||
var editingName: ItemListAvatarAndNameInfoItemName?
|
||||
@ -738,16 +743,20 @@ private func deviceContactInfoEntries(account: Account, engine: TelegramEngine,
|
||||
|
||||
var addressIndex = 0
|
||||
for address in contactData.addresses {
|
||||
let signal = geocodeLocation(address: address.asPostalAddress)
|
||||
|> mapToSignal { coordinates -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
|
||||
if let (latitude, longitude) = coordinates {
|
||||
let resource = MapSnapshotMediaResource(latitude: latitude, longitude: longitude, width: 90, height: 90)
|
||||
return chatMapSnapshotImage(engine: engine, resource: resource)
|
||||
} else {
|
||||
return .single({ _ in return nil })
|
||||
let signal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>
|
||||
if let context = context as? ShareControllerAppAccountContext {
|
||||
signal = geocodeLocation(address: address.asPostalAddress)
|
||||
|> mapToSignal { coordinates -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
|
||||
if let (latitude, longitude) = coordinates {
|
||||
let resource = MapSnapshotMediaResource(latitude: latitude, longitude: longitude, width: 90, height: 90)
|
||||
return chatMapSnapshotImage(engine: context.context.engine, resource: resource)
|
||||
} else {
|
||||
return .single({ _ in return nil })
|
||||
}
|
||||
}
|
||||
} else {
|
||||
signal = .single({ _ in return nil })
|
||||
}
|
||||
|
||||
entries.append(.address(entries.count, addressIndex, presentationData.theme, localizedGenericContactFieldLabel(label: address.label, strings: presentationData.strings), address, signal, selecting ? !state.excludedComponents.contains(.address(address)) : nil))
|
||||
addressIndex += 1
|
||||
}
|
||||
@ -828,7 +837,7 @@ private final class DeviceContactInfoController: ItemListController, MFMessageCo
|
||||
}
|
||||
}
|
||||
|
||||
public func deviceContactInfoController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, subject: DeviceContactInfoSubject, completed: (() -> Void)?, cancelled: (() -> Void)?) -> ViewController {
|
||||
public func deviceContactInfoController(context: ShareControllerAccountContext, environment: ShareControllerEnvironment, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, subject: DeviceContactInfoSubject, completed: (() -> Void)?, cancelled: (() -> Void)?) -> ViewController {
|
||||
var initialState = DeviceContactInfoState()
|
||||
if case let .create(peer, contactData, _, _, _) = subject {
|
||||
var peerPhoneNumber: String?
|
||||
@ -876,7 +885,11 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
|
||||
|
||||
var displayCopyContextMenuImpl: ((DeviceContactInfoEntryTag, String) -> Void)?
|
||||
|
||||
let presentationData = environment.presentationData
|
||||
let callImpl: (String) -> Void = { number in
|
||||
guard let context = (context as? ShareControllerAppAccountContext)?.context else {
|
||||
return
|
||||
}
|
||||
let user: Signal<TelegramUser?, NoError>
|
||||
if let peer = subject.peer {
|
||||
user = context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peer.id))
|
||||
@ -890,10 +903,10 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
|
||||
} else {
|
||||
user = .single(nil)
|
||||
}
|
||||
|
||||
let _ = (user
|
||||
|> deliverOnMainQueue).start(next: { user in
|
||||
if let user = user, let phone = user.phone, formatPhoneNumber(phone) == formatPhoneNumber(number) {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = ActionSheetController(presentationData: presentationData)
|
||||
let dismissAction: () -> Void = { [weak controller] in
|
||||
controller?.dismissAnimated()
|
||||
@ -932,7 +945,13 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
|
||||
shareViaException = shareViaExceptionValue
|
||||
}
|
||||
|
||||
let arguments = DeviceContactInfoControllerArguments(context: context, isPlain: !isShare, updateEditingName: { editingName in
|
||||
let accountContext: AccountContext?
|
||||
if let context = context as? ShareControllerAppAccountContext {
|
||||
accountContext = context.context
|
||||
} else {
|
||||
accountContext = nil
|
||||
}
|
||||
let arguments = DeviceContactInfoControllerArguments(accountContext: accountContext, isPlain: !isShare, updateEditingName: { editingName in
|
||||
updateState { state in
|
||||
var state = state
|
||||
if let _ = state.editingState {
|
||||
@ -952,6 +971,9 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
|
||||
return state
|
||||
}
|
||||
}, updatePhoneLabel: { id, currentLabel in
|
||||
guard let context = (context as? ShareControllerAppAccountContext)?.context else {
|
||||
return
|
||||
}
|
||||
pushControllerImpl?(phoneLabelController(context: context, currentLabel: currentLabel, completion: { value in
|
||||
updateState { state in
|
||||
var state = state
|
||||
@ -1000,7 +1022,6 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
|
||||
if subject.contactData.basicData.phoneNumbers.count == 1 {
|
||||
inviteAction(subject.contactData.basicData.phoneNumbers[0].value)
|
||||
} else {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = ActionSheetController(presentationData: presentationData)
|
||||
let dismissAction: () -> Void = { [weak controller] in
|
||||
controller?.dismissAnimated()
|
||||
@ -1020,7 +1041,7 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
|
||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}
|
||||
case .createContact:
|
||||
pushControllerImpl?(deviceContactInfoController(context: context, subject: .create(peer: subject.peer, contactData: subject.contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in
|
||||
pushControllerImpl?(deviceContactInfoController(context: context, environment: environment, subject: .create(peer: subject.peer, contactData: subject.contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in
|
||||
dismissImpl?(false)
|
||||
}), completed: nil, cancelled: nil))
|
||||
case .addToExisting:
|
||||
@ -1059,9 +1080,9 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
|
||||
})
|
||||
|
||||
let hiddenAvatarPromise = Promise<TelegramMediaImageRepresentation?>(nil)
|
||||
let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData
|
||||
let updatedPresentationData = updatedPresentationData?.signal ?? environment.updatedPresentationData
|
||||
let previousEditingPhoneIds = Atomic<Set<Int64>?>(value: nil)
|
||||
let signal = combineLatest(presentationData, statePromise.get(), contactData, hiddenAvatarPromise.get())
|
||||
let signal = combineLatest(updatedPresentationData, statePromise.get(), contactData, hiddenAvatarPromise.get())
|
||||
|> map { presentationData, state, peerAndContactData, hiddenAvatar -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
var presentationData = presentationData
|
||||
let updatedTheme = presentationData.theme.withModalBlocksBackground()
|
||||
@ -1116,6 +1137,9 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
|
||||
|
||||
rightNavigationButton = ItemListNavigationButton(content: .text(isShare ? presentationData.strings.Common_Done : presentationData.strings.Compose_Create), style: .bold, enabled: (isShare || !filteredPhoneNumbers.isEmpty) && composedContactData != nil, action: {
|
||||
if let composedContactData = composedContactData {
|
||||
guard let context = (context as? ShareControllerAppAccountContext)?.context else {
|
||||
return
|
||||
}
|
||||
var addToPrivacyExceptions = false
|
||||
updateState { state in
|
||||
var state = state
|
||||
@ -1129,7 +1153,7 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
|
||||
if share, filteredPhoneNumbers.count <= 1, let peer = peer {
|
||||
addContactDisposable.set((context.engine.contacts.addContactInteractively(peerId: peer.id, firstName: composedContactData.basicData.firstName, lastName: composedContactData.basicData.lastName, phoneNumber: filteredPhoneNumbers.first?.value ?? "", addToPrivacyExceptions: shareViaException && addToPrivacyExceptions)
|
||||
|> deliverOnMainQueue).start(error: { _ in
|
||||
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: (environment.presentationData, updatedPresentationData), title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
}, completed: {
|
||||
let _ = (contactDataManager.createContactWithData(composedContactData)
|
||||
|> deliverOnMainQueue).start(next: { contactIdAndData in
|
||||
@ -1250,7 +1274,7 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
|
||||
focusItemTag = DeviceContactInfoEntryTag.editingPhone(insertedPhoneId)
|
||||
}
|
||||
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: deviceContactInfoEntries(account: context.account, engine: context.engine, presentationData: presentationData, peer: peerAndContactData.0, isShare: isShare, shareViaException: shareViaException, contactData: peerAndContactData.2, isContact: peerAndContactData.1 != nil, state: state, selecting: selecting, editingPhoneNumbers: editingPhones, hiddenAvatar: hiddenAvatar), style: isShare ? .blocks : .plain, focusItemTag: focusItemTag)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: deviceContactInfoEntries(context: context, presentationData: presentationData, peer: peerAndContactData.0, isShare: isShare, shareViaException: shareViaException, contactData: peerAndContactData.2, isContact: peerAndContactData.1 != nil, state: state, selecting: selecting, editingPhoneNumbers: editingPhones, hiddenAvatar: hiddenAvatar), style: isShare ? .blocks : .plain, focusItemTag: focusItemTag)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
@ -1258,24 +1282,27 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
|
||||
actionsDisposable.dispose()
|
||||
}
|
||||
|
||||
let controller = DeviceContactInfoController(context: context, state: signal)
|
||||
let controller = DeviceContactInfoController(presentationData: ItemListPresentationData(environment.presentationData), updatedPresentationData: environment.updatedPresentationData |> map { ItemListPresentationData($0) }, state: signal, tabBarItem: nil)
|
||||
controller.navigationPresentation = .modal
|
||||
addToExistingImpl = { [weak controller] in
|
||||
guard let controller = controller else {
|
||||
guard let controller, let accountContext = (context as? ShareControllerAppAccountContext)?.context else {
|
||||
return
|
||||
}
|
||||
addContactToExisting(context: context, parentController: controller, contactData: subject.contactData, completion: { peer, contactId, contactData in
|
||||
replaceControllerImpl?(deviceContactInfoController(context: context, subject: .vcard(peer?._asPeer(), contactId, contactData), completed: nil, cancelled: nil))
|
||||
addContactToExisting(context: accountContext, parentController: controller, contactData: subject.contactData, completion: { peer, contactId, contactData in
|
||||
replaceControllerImpl?(deviceContactInfoController(context: context, environment: environment, subject: .vcard(peer?._asPeer(), contactId, contactData), completed: nil, cancelled: nil))
|
||||
})
|
||||
}
|
||||
openChatImpl = { [weak controller] peerId in
|
||||
guard let controller, let context = (context as? ShareControllerAppAccountContext)?.context else {
|
||||
return
|
||||
}
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
guard let peer = peer else {
|
||||
|> deliverOnMainQueue).start(next: { [weak controller] peer in
|
||||
guard let peer, let controller else {
|
||||
return
|
||||
}
|
||||
|
||||
if let navigationController = (controller?.navigationController as? NavigationController) {
|
||||
if let navigationController = (controller.navigationController as? NavigationController) {
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer)))
|
||||
}
|
||||
})
|
||||
@ -1301,7 +1328,7 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
|
||||
}
|
||||
}
|
||||
inviteImpl = { [weak controller] numbers in
|
||||
controller?.inviteContact(presentationData: context.sharedContext.currentPresentationData.with { $0 }, numbers: numbers)
|
||||
controller?.inviteContact(presentationData: environment.presentationData, numbers: numbers)
|
||||
}
|
||||
openAddressImpl = { [weak controller] address in
|
||||
guard let _ = controller else {
|
||||
@ -1309,7 +1336,7 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
|
||||
}
|
||||
}
|
||||
openUrlImpl = { [weak controller] url in
|
||||
guard let controller = controller else {
|
||||
guard let controller, let context = (context as? ShareControllerAppAccountContext)?.context else {
|
||||
return
|
||||
}
|
||||
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: url, forceExternal: false, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: controller.navigationController as? NavigationController, dismissInput: { [weak controller] in
|
||||
@ -1319,7 +1346,7 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
|
||||
|
||||
displayCopyContextMenuImpl = { [weak controller] tag, value in
|
||||
if let strongController = controller {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let presentationData = environment.presentationData
|
||||
var resultItemNode: ListViewItemNode?
|
||||
let _ = strongController.frameForItemNode({ itemNode in
|
||||
if let itemNode = itemNode as? ItemListTextWithLabelItemNode {
|
||||
@ -1350,6 +1377,9 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
|
||||
}
|
||||
}
|
||||
openAvatarImpl = { [weak controller] peer in
|
||||
guard let context = (context as? ShareControllerAppAccountContext)?.context else {
|
||||
return
|
||||
}
|
||||
let avatarController = AvatarGalleryController(context: context, peer: peer, replaceRootController: { _, _ in
|
||||
})
|
||||
hiddenAvatarPromise.set(
|
||||
@ -1413,7 +1443,7 @@ private func addContactToExisting(context: AccountContext, parentController: Vie
|
||||
let _ = (dataSignal
|
||||
|> deliverOnMainQueue).start(next: { peer, stableId in
|
||||
guard let stableId = stableId else {
|
||||
parentController.present(deviceContactInfoController(context: context, subject: .create(peer: peer?._asPeer(), contactData: contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in
|
||||
parentController.present(deviceContactInfoController(context: ShareControllerAppAccountContext(context: context), environment: ShareControllerAppEnvironment(sharedContext: context.sharedContext), subject: .create(peer: peer?._asPeer(), contactData: contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in
|
||||
}), completed: nil, cancelled: nil), in: .window(.root))
|
||||
return
|
||||
}
|
||||
@ -1459,7 +1489,7 @@ func addContactOptionsController(context: AccountContext, peer: EnginePeer?, con
|
||||
controller.setItemGroups([
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: presentationData.strings.Profile_CreateNewContact, action: { [weak controller] in
|
||||
controller?.present(context.sharedContext.makeDeviceContactInfoController(context: context, subject: .create(peer: peer?._asPeer(), contactData: contactData, isSharing: peer != nil, shareViaException: false, completion: { _, _, _ in
|
||||
controller?.present(context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: context), environment: ShareControllerAppEnvironment(sharedContext: context.sharedContext), subject: .create(peer: peer?._asPeer(), contactData: contactData, isSharing: peer != nil, shareViaException: false, completion: { _, _, _ in
|
||||
}), completed: nil, cancelled: nil), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
dismissAction()
|
||||
}),
|
||||
@ -1476,3 +1506,32 @@ func addContactOptionsController(context: AccountContext, peer: EnginePeer?, con
|
||||
])
|
||||
return controller
|
||||
}
|
||||
|
||||
public func pushContactContextOptionsController(context: AccountContext, contextController: ContextControllerProtocol, presentationData: PresentationData, peer: EnginePeer?, contactData: DeviceContactExtendedData, parentController: ViewController, push: @escaping (ViewController) -> Void) {
|
||||
var items: [ContextMenuItem] = []
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: presentationData.strings.Common_Back, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor) }, iconPosition: .left, action: { c, _ in
|
||||
c?.popItems()
|
||||
}))
|
||||
)
|
||||
items.append(.separator)
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: presentationData.strings.Chat_Context_Phone_CreateNewContact, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
push(context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: context), environment: ShareControllerAppEnvironment(sharedContext: context.sharedContext), subject: .create(peer: peer?._asPeer(), contactData: contactData, isSharing: peer != nil, shareViaException: false, completion: { _, _, _ in
|
||||
}), completed: nil, cancelled: nil))
|
||||
}))
|
||||
)
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: presentationData.strings.Chat_Context_Phone_AddToExistingContact, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MoveToContacts"), color: theme.contextMenu.primaryColor) }, action: { [weak parentController] _, f in
|
||||
f(.default)
|
||||
guard let parentController else {
|
||||
return
|
||||
}
|
||||
addContactToExisting(context: context, parentController: parentController, contactData: contactData, completion: { peer, contactId, contactData in
|
||||
})
|
||||
}))
|
||||
)
|
||||
contextController.pushItems(items: .single(ContextController.Items(content: .list(items))))
|
||||
}
|
||||
|
@ -58,8 +58,8 @@ public func openAddPersonContactImpl(context: AccountContext, updatedPresentatio
|
||||
if let statusSettings = statusSettings {
|
||||
shareViaException = statusSettings.contains(.addExceptionWhenAddingContact)
|
||||
}
|
||||
|
||||
pushController(deviceContactInfoController(context: context, updatedPresentationData: updatedPresentationData, subject: .create(peer: user, contactData: contactData, isSharing: true, shareViaException: shareViaException, completion: { peer, stableId, contactData in
|
||||
|
||||
pushController(deviceContactInfoController(context: ShareControllerAppAccountContext(context: context), environment: ShareControllerAppEnvironment(sharedContext: context.sharedContext), updatedPresentationData: updatedPresentationData, subject: .create(peer: user, contactData: contactData, isSharing: true, shareViaException: shareViaException, completion: { peer, stableId, contactData in
|
||||
if let peer = peer as? TelegramUser {
|
||||
completion()
|
||||
|
||||
|
@ -304,18 +304,6 @@ private func collectExternalShareItems(strings: PresentationStrings, dateTimeFor
|
||||
})
|
||||
}
|
||||
|
||||
public protocol ShareControllerEnvironment: AnyObject {
|
||||
var presentationData: PresentationData { get }
|
||||
var updatedPresentationData: Signal<PresentationData, NoError> { get }
|
||||
var isMainApp: Bool { get }
|
||||
var energyUsageSettings: EnergyUsageSettings { get }
|
||||
|
||||
var mediaManager: MediaManager? { get }
|
||||
|
||||
func setAccountUserInterfaceInUse(id: AccountRecordId) -> Disposable
|
||||
func donateSendMessageIntent(account: ShareControllerAccountContext, peerIds: [EnginePeer.Id])
|
||||
}
|
||||
|
||||
public final class ShareControllerAppEnvironment: ShareControllerEnvironment {
|
||||
let sharedContext: SharedAccountContext
|
||||
|
||||
@ -353,19 +341,6 @@ public final class ShareControllerAppEnvironment: ShareControllerEnvironment {
|
||||
}
|
||||
}
|
||||
|
||||
public protocol ShareControllerAccountContext: AnyObject {
|
||||
var accountId: AccountRecordId { get }
|
||||
var accountPeerId: EnginePeer.Id { get }
|
||||
var stateManager: AccountStateManager { get }
|
||||
var engineData: TelegramEngine.EngineData { get }
|
||||
var animationCache: AnimationCache { get }
|
||||
var animationRenderer: MultiAnimationRenderer { get }
|
||||
var contentSettings: ContentSettings { get }
|
||||
var appConfiguration: AppConfiguration { get }
|
||||
|
||||
func resolveInlineStickers(fileIds: [Int64]) -> Signal<[Int64: TelegramMediaFile], NoError>
|
||||
}
|
||||
|
||||
public final class ShareControllerAppAccountContext: ShareControllerAccountContext {
|
||||
public let context: AccountContext
|
||||
|
||||
|
@ -349,7 +349,6 @@ final class ShareControllerNode: ViewControllerTracingNode, ASScrollViewDelegate
|
||||
var disabledPeerSelected: ((EnginePeer) -> Void)?
|
||||
|
||||
let ready = Promise<Bool>()
|
||||
private var didSetReady = false
|
||||
|
||||
private var controllerInteraction: ShareControllerInteraction?
|
||||
|
||||
|
@ -175,7 +175,7 @@ public final class ChatBotInfoItemNode: ListViewItemNode {
|
||||
break
|
||||
case .ignore:
|
||||
return .fail
|
||||
case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy, .largeEmoji, .customEmoji:
|
||||
case .url, .phone, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy, .largeEmoji, .customEmoji:
|
||||
return .waitForSingleTap
|
||||
}
|
||||
}
|
||||
|
@ -141,6 +141,7 @@ public struct ChatMessageBubbleContentTapAction {
|
||||
public enum Content {
|
||||
case none
|
||||
case url(Url)
|
||||
case phone(String)
|
||||
case textMention(String)
|
||||
case peerMention(peerId: PeerId, mention: String, openProfile: Bool)
|
||||
case botCommand(String)
|
||||
|
@ -770,24 +770,24 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
}
|
||||
|
||||
self.mainContextSourceNode.willUpdateIsExtractedToContextPreview = { [weak self] isExtractedToContextPreview, _ in
|
||||
guard let strongSelf = self, let _ = strongSelf.item else {
|
||||
guard let self, let _ = self.item else {
|
||||
return
|
||||
}
|
||||
for contentNode in strongSelf.contentNodes {
|
||||
for contentNode in self.contentNodes {
|
||||
contentNode.willUpdateIsExtractedToContextPreview(isExtractedToContextPreview)
|
||||
}
|
||||
}
|
||||
self.mainContextSourceNode.isExtractedToContextPreviewUpdated = { [weak self] isExtractedToContextPreview in
|
||||
guard let strongSelf = self else {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
strongSelf.backgroundWallpaperNode.setMaskMode(strongSelf.backgroundMaskMode)
|
||||
strongSelf.backgroundNode.setMaskMode(strongSelf.backgroundMaskMode)
|
||||
if !isExtractedToContextPreview, let (rect, size) = strongSelf.absoluteRect {
|
||||
strongSelf.updateAbsoluteRect(rect, within: size)
|
||||
self.backgroundWallpaperNode.setMaskMode(self.backgroundMaskMode)
|
||||
self.backgroundNode.setMaskMode(self.backgroundMaskMode)
|
||||
if !isExtractedToContextPreview, let (rect, size) = self.absoluteRect {
|
||||
self.updateAbsoluteRect(rect, within: size)
|
||||
}
|
||||
|
||||
for contentNode in strongSelf.contentNodes {
|
||||
|
||||
for contentNode in self.contentNodes {
|
||||
contentNode.updateIsExtractedToContextPreview(isExtractedToContextPreview)
|
||||
}
|
||||
}
|
||||
@ -811,7 +811,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
strongSelf.applyAbsoluteOffsetSpringInternal(value: value, duration: duration, damping: damping)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
@ -1150,15 +1150,15 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
let contentNodePoint = strongSelf.view.convert(point, to: contentNode.view)
|
||||
let tapAction = contentNode.tapActionAtPoint(contentNodePoint, gesture: .tap, isEstimating: true)
|
||||
switch tapAction.content {
|
||||
case .none:
|
||||
if let _ = strongSelf.item?.controllerInteraction.tapMessage {
|
||||
return .waitForSingleTap
|
||||
}
|
||||
break
|
||||
case .ignore:
|
||||
return .fail
|
||||
case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy, .largeEmoji, .customEmoji:
|
||||
case .none:
|
||||
if let _ = strongSelf.item?.controllerInteraction.tapMessage {
|
||||
return .waitForSingleTap
|
||||
}
|
||||
break
|
||||
case .ignore:
|
||||
return .fail
|
||||
case .url, .phone, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy, .largeEmoji, .customEmoji:
|
||||
return .waitForSingleTap
|
||||
}
|
||||
}
|
||||
|
||||
@ -4589,6 +4589,16 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
item.controllerInteraction.openUrl(ChatControllerInteraction.OpenUrl(url: url.url, concealed: url.concealed, message: item.content.firstMessage, allowInlineWebpageResolution: url.allowInlineWebpageResolution, progress: tapAction.activate?()))
|
||||
}, contextMenuOnLongPress: !tapAction.hasLongTapAction))
|
||||
}
|
||||
case let .phone(number):
|
||||
return .action(InternalBubbleTapAction.Action({ [weak self] in
|
||||
guard let self, let item = self.item, let contentNode = self.contextContentNodeForPhoneNumber(number) else {
|
||||
return
|
||||
}
|
||||
|
||||
self.addSubnode(contentNode)
|
||||
|
||||
item.controllerInteraction.openPhoneContextMenu(ChatControllerInteraction.OpenPhone(number: number, message: item.content.firstMessage, contentNode: contentNode, messageNode: self, progress: tapAction.activate?()))
|
||||
}, contextMenuOnLongPress: !tapAction.hasLongTapAction))
|
||||
case let .peerMention(peerId, _, openProfile):
|
||||
return .action(InternalBubbleTapAction.Action { [weak self] in
|
||||
if let item = self?.item {
|
||||
@ -4751,6 +4761,16 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
} else {
|
||||
disableDefaultPressAnimation = true
|
||||
}
|
||||
case let .phone(number):
|
||||
return .action(InternalBubbleTapAction.Action({ [weak self] in
|
||||
guard let self, let item = self.item, let contentNode = self.contextContentNodeForPhoneNumber(number) else {
|
||||
return
|
||||
}
|
||||
|
||||
self.addSubnode(contentNode)
|
||||
|
||||
item.controllerInteraction.openPhoneContextMenu(ChatControllerInteraction.OpenPhone(number: number, message: item.content.firstMessage, contentNode: contentNode, messageNode: self, progress: tapAction.activate?()))
|
||||
}, contextMenuOnLongPress: !tapAction.hasLongTapAction))
|
||||
case let .peerMention(peerId, mention, _):
|
||||
return .action(InternalBubbleTapAction.Action {
|
||||
item.controllerInteraction.longTap(.peerMention(peerId, mention), message)
|
||||
@ -4818,6 +4838,39 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
return nil
|
||||
}
|
||||
|
||||
private func contextContentNodeForPhoneNumber(_ number: String) -> ContextExtractedContentContainingNode? {
|
||||
guard let item = self.item else {
|
||||
return nil
|
||||
}
|
||||
let containingNode = ContextExtractedContentContainingNode()
|
||||
|
||||
let incoming = item.content.effectivelyIncoming(item.context.account.peerId, associatedData: item.associatedData)
|
||||
|
||||
let textNode = ImmediateTextNode()
|
||||
textNode.attributedText = NSAttributedString(string: number, font: Font.regular(item.presentationData.fontSize.baseDisplaySize), textColor: incoming ? item.presentationData.theme.theme.chat.message.incoming.linkTextColor : item.presentationData.theme.theme.chat.message.outgoing.linkTextColor)
|
||||
let textSize = textNode.updateLayout(CGSize(width: 1000.0, height: 100.0))
|
||||
|
||||
let backgroundNode = ASDisplayNode()
|
||||
backgroundNode.backgroundColor = (incoming ? item.presentationData.theme.theme.chat.message.incoming.bubble.withoutWallpaper.fill : item.presentationData.theme.theme.chat.message.outgoing.bubble.withoutWallpaper.fill).first ?? .black
|
||||
backgroundNode.clipsToBounds = true
|
||||
backgroundNode.cornerRadius = 10.0
|
||||
|
||||
let insets = UIEdgeInsets(top: 5.0, left: 8.0, bottom: 5.0, right: 8.0)
|
||||
let backgroundSize = CGSize(width: textSize.width + insets.left + insets.right, height: textSize.height + insets.top + insets.bottom)
|
||||
backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: backgroundSize)
|
||||
textNode.frame = CGRect(origin: CGPoint(x: insets.left, y: insets.top), size: textSize)
|
||||
backgroundNode.addSubnode(textNode)
|
||||
|
||||
containingNode.frame = CGRect(origin: CGPoint(x: self.backgroundNode.frame.minX + 3.0, y: 1.0), size: CGSize(width: backgroundSize.width, height: backgroundSize.height + 20.0))
|
||||
containingNode.contentNode.frame = CGRect(origin: .zero, size: backgroundSize)
|
||||
containingNode.contentRect = CGRect(origin: .zero, size: backgroundSize)
|
||||
containingNode.contentNode.addSubnode(backgroundNode)
|
||||
|
||||
containingNode.contentNode.alpha = 0.0
|
||||
|
||||
return containingNode
|
||||
}
|
||||
|
||||
private func traceSelectionNodes(parent: ASDisplayNode, point: CGPoint) -> ASDisplayNode? {
|
||||
if let parent = parent as? FileMessageSelectionNode, parent.bounds.contains(point) {
|
||||
return parent
|
||||
|
@ -857,7 +857,15 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
urlRange = urlRangeValue
|
||||
concealed = !doesUrlMatchText(url: url, text: attributeText, fullText: fullText)
|
||||
}
|
||||
return ChatMessageBubbleContentTapAction(content: .url(ChatMessageBubbleContentTapAction.Url(url: url, concealed: concealed)), activate: { [weak self] in
|
||||
|
||||
var content: ChatMessageBubbleContentTapAction.Content
|
||||
if url.hasPrefix("tel:") {
|
||||
content = .phone(url.replacingOccurrences(of: "tel:", with: ""))
|
||||
} else {
|
||||
content = .url(ChatMessageBubbleContentTapAction.Url(url: url, concealed: concealed))
|
||||
}
|
||||
|
||||
return ChatMessageBubbleContentTapAction(content: content, activate: { [weak self] in
|
||||
guard let self else {
|
||||
return nil
|
||||
}
|
||||
|
@ -614,6 +614,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
}, openRecommendedChannelContextMenu: { _, _, _ in
|
||||
}, openGroupBoostInfo: { _, _ in
|
||||
}, openStickerEditor: {
|
||||
}, openPhoneContextMenu: { _ in
|
||||
}, openAgeRestrictedMessageMedia: { _, _ in
|
||||
}, requestMessageUpdate: { _, _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, dismissTextInput: {
|
||||
|
@ -148,6 +148,22 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
|
||||
}
|
||||
}
|
||||
|
||||
public struct OpenPhone {
|
||||
public var number: String
|
||||
public var message: Message
|
||||
public var contentNode: ContextExtractedContentContainingNode
|
||||
public var messageNode: ASDisplayNode
|
||||
public var progress: Promise<Bool>?
|
||||
|
||||
public init(number: String, message: Message, contentNode: ContextExtractedContentContainingNode, messageNode: ASDisplayNode, progress: Promise<Bool>? = nil) {
|
||||
self.number = number
|
||||
self.message = message
|
||||
self.contentNode = contentNode
|
||||
self.messageNode = messageNode
|
||||
self.progress = progress
|
||||
}
|
||||
}
|
||||
|
||||
public let openMessage: (Message, OpenMessageParams) -> Bool
|
||||
public let openPeer: (EnginePeer, ChatControllerInteractionNavigateToPeer, MessageReference?, OpenPeerSource) -> Void
|
||||
public let openPeerMention: (String, Promise<Bool>?) -> Void
|
||||
@ -242,6 +258,8 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
|
||||
public let openRecommendedChannelContextMenu: (EnginePeer, UIView, ContextGesture?) -> Void
|
||||
public let openGroupBoostInfo: (EnginePeer.Id?, Int) -> Void
|
||||
public let openStickerEditor: () -> Void
|
||||
public let openPhoneContextMenu: (OpenPhone) -> Void
|
||||
public let openAgeRestrictedMessageMedia: (Message, @escaping () -> Void) -> Void
|
||||
|
||||
public let requestMessageUpdate: (MessageId, Bool) -> Void
|
||||
public let cancelInteractiveKeyboardGestures: () -> Void
|
||||
@ -367,6 +385,8 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
|
||||
openRecommendedChannelContextMenu: @escaping (EnginePeer, UIView, ContextGesture?) -> Void,
|
||||
openGroupBoostInfo: @escaping (EnginePeer.Id?, Int) -> Void,
|
||||
openStickerEditor: @escaping () -> Void,
|
||||
openPhoneContextMenu: @escaping (OpenPhone) -> Void,
|
||||
openAgeRestrictedMessageMedia: @escaping (Message, @escaping () -> Void) -> Void,
|
||||
requestMessageUpdate: @escaping (MessageId, Bool) -> Void,
|
||||
cancelInteractiveKeyboardGestures: @escaping () -> Void,
|
||||
dismissTextInput: @escaping () -> Void,
|
||||
@ -472,6 +492,8 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
|
||||
self.openRecommendedChannelContextMenu = openRecommendedChannelContextMenu
|
||||
self.openGroupBoostInfo = openGroupBoostInfo
|
||||
self.openStickerEditor = openStickerEditor
|
||||
self.openPhoneContextMenu = openPhoneContextMenu
|
||||
self.openAgeRestrictedMessageMedia = openAgeRestrictedMessageMedia
|
||||
|
||||
self.requestMessageUpdate = requestMessageUpdate
|
||||
self.cancelInteractiveKeyboardGestures = cancelInteractiveKeyboardGestures
|
||||
|
@ -3326,6 +3326,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}, openRecommendedChannelContextMenu: { _, _, _ in
|
||||
}, openGroupBoostInfo: { _, _ in
|
||||
}, openStickerEditor: {
|
||||
}, openPhoneContextMenu: { _ in
|
||||
}, openAgeRestrictedMessageMedia: { _, _ in
|
||||
}, requestMessageUpdate: { _, _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, dismissTextInput: {
|
||||
|
@ -492,19 +492,13 @@ public class ShareRootControllerImpl {
|
||||
|
||||
let displayShare: () -> Void = {
|
||||
var cancelImpl: (() -> Void)?
|
||||
let _ = cancelImpl
|
||||
|
||||
let beginShare: () -> Void = {
|
||||
let requestUserInteraction: ([UnpreparedShareItemContent]) -> Signal<[PreparedShareItemContent], NoError> = { content in
|
||||
return Signal { [weak self] subscriber in
|
||||
switch content[0] {
|
||||
case let .contact(data):
|
||||
#if !DEBUG
|
||||
//qwefqwfqwefw
|
||||
#endif
|
||||
let _ = data
|
||||
let _ = self
|
||||
/*let controller = deviceContactInfoController(context: context, subject: .filter(peer: nil, contactId: nil, contactData: data, completion: { peer, contactData in
|
||||
let controller = deviceContactInfoController(context: context, environment: environment, subject: .filter(peer: nil, contactId: nil, contactData: data, completion: { peer, contactData in
|
||||
let phone = contactData.basicData.phoneNumbers[0].value
|
||||
if let vCardData = contactData.serializedVCard() {
|
||||
subscriber.putNext([.media(.media(.standalone(media: TelegramMediaContact(firstName: contactData.basicData.firstName, lastName: contactData.basicData.lastName, phoneNumber: phone, peerId: nil, vCardData: vCardData))))])
|
||||
@ -517,7 +511,7 @@ public class ShareRootControllerImpl {
|
||||
if let strongSelf = self, let window = strongSelf.mainWindow {
|
||||
controller.presentationArguments = ViewControllerPresentationArguments(presentationAnimation: .modalSheet)
|
||||
window.present(controller, on: .root)
|
||||
}*/
|
||||
}
|
||||
break
|
||||
}
|
||||
return EmptyDisposable
|
||||
|
@ -1762,7 +1762,7 @@ final class StoryItemSetContainerSendMessage {
|
||||
|
||||
self.sendMessages(view: view, peer: targetPeer, messages: enqueueMessages, silentPosting: silent, scheduleTime: scheduleTime)
|
||||
} else {
|
||||
let contactController = component.context.sharedContext.makeDeviceContactInfoController(context: component.context, subject: .filter(peer: peerAndContactData.0?._asPeer(), contactId: nil, contactData: contactData, completion: { [weak self, weak view] peer, contactData in
|
||||
let contactController = component.context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: component.context), environment: ShareControllerAppEnvironment(sharedContext: component.context.sharedContext), subject: .filter(peer: peerAndContactData.0?._asPeer(), contactId: nil, contactData: contactData, completion: { [weak self, weak view] peer, contactData in
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "ic_lt_adduser.pdf"
|
||||
"filename" : "ic_lt_adduser.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
BIN
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/AgeMark.imageset/18on_24.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/AgeMark.imageset/18on_24.pdf
vendored
Normal file
Binary file not shown.
12
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/AgeMark.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/AgeMark.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "18on_24.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/AgeUnmark.imageset/18off_24.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/AgeUnmark.imageset/18off_24.pdf
vendored
Normal file
Binary file not shown.
12
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/AgeUnmark.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/AgeUnmark.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "18off_24.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
12
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Telegram.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Telegram.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "tlogo_24.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Telegram.imageset/tlogo_24.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Telegram.imageset/tlogo_24.pdf
vendored
Normal file
Binary file not shown.
12
submodules/TelegramUI/Images.xcassets/Chat/Message/AgeRestricted.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Message/AgeRestricted.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "eyeoff_30.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
143
submodules/TelegramUI/Images.xcassets/Chat/Message/AgeRestricted.imageset/eyeoff_30.pdf
vendored
Normal file
143
submodules/TelegramUI/Images.xcassets/Chat/Message/AgeRestricted.imageset/eyeoff_30.pdf
vendored
Normal file
@ -0,0 +1,143 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< /Filter /FlateDecode
|
||||
/Type /XObject
|
||||
/Length 2 0 R
|
||||
/Group << /Type /Group
|
||||
/S /Transparency
|
||||
>>
|
||||
/Subtype /Form
|
||||
/Resources << >>
|
||||
/BBox [ 0.000000 0.000000 24.000000 24.000000 ]
|
||||
>>
|
||||
stream
|
||||
xm•Í®E…÷ý½F¢R¶Ë.×<16>X<03>0
|
||||
é&ŠÄóçs§§§ós7S÷Œ<C592><7F>=ï~{ÿÿ¿<C3BF>÷þþËþë_Û»×<C397>OÛ›´~üíýùøùz]ßY±Ôrmtµ1öLJí2ûþñéñ‘À™ÃÄwm¹¨ôý`äên»x“c*Ilê˜d»A2§ö¼¹>H·RÖˆ§û“|/hز ÙÍUÇ<55>®¸Vä/h‚o‰°j•ªà,ïñYm\®Ä‹ÖçòYñžyoÐYÝÝõêBŒ¬kЧî)g)ÝWˆÀ¯›çht–Ùwokyï« ìêš{´%@^ñf“è±rŸÄ›šP4"ø:yøÐQ®3,`¶˜´v¸Òk'žôJ†å.ÚVg¸NŠ‹[<5B>äËzl“QÛ ·H¸‰'®ÚÒdRSµ3R±Ò¦«Ï.¸þ@oÛ?›·¹¬;#;ŠŽD/ÙÌ^PĘALyFæš`<60>‡UŸg…Ù–¥Èâq"ëKuFÞF|"9zsff1@L‘J!+3"?ƒ•Â
|
||||
À<EFBFBD><EFBFBD>µ„èrÄ/ä±–Bˆƒg
|
||||
fD¡jR\Ðl^VEîÄ(R<>U&£cøS‚9÷b×X·€\QúÀUÚ¢(-ƒ]ƒ}Ÿ64jF"¬r¦ˆæ¡s¢¯º—r<E28094>¤ë:éðZÑ'ÄW¶²¼ð‚J$c9R¸<52>dc(p
|
||||
F7¨þÁàè<>}[,m<>þ”l<E2809D>œW/š- U±±±jQYEéE7‹Òä´ôtZ{lƒÆQb
ƒur¼<72>‘Ö¼Ñ;wm™T5t ¬Æ…Ü8¹0ÎJLgGYV˜¶:”‡ÜJ"'R‚ t¥œCƒ£QWA<57>õ
·¥ÌÏèì<C3A8>"C ËÁ5Xôæ“ÕwªÇéÚr@4;´äVsyÒ}–Áî>‘*¿Ž
T\<ù“†4i¨.«z&‘n§¦~Ö2pqžš‚ÒÕjáÎSƒç7c«aB<61>-zÀ5{@:ÃDµsvw0‚)tDƒaÉ'_u-<2D>K†¤b#9›µ<E280BA>\}áHS:Òu(–û\…X¤Ï¨Š!U—…\”͉”BµsëÊžXUŠUí…NJ¾<4A>›nXDvÄVˆÕ]§›A…|Ýs1ñ÷OÛÇí<C387>í3Ü|¨
|
||||
endstream
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
868
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
<< /Type /XObject
|
||||
/Length 4 0 R
|
||||
/Group << /Type /Group
|
||||
/S /Transparency
|
||||
>>
|
||||
/Subtype /Form
|
||||
/Resources << >>
|
||||
/BBox [ 0.000000 0.000000 24.000000 24.000000 ]
|
||||
>>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
0.000000 12.800001 m
|
||||
0.000000 16.720367 0.000000 18.680552 0.762954 20.177933 c
|
||||
1.434068 21.495068 2.504932 22.565931 3.822066 23.237045 c
|
||||
5.319448 24.000000 7.279633 24.000000 11.200000 24.000000 c
|
||||
12.800001 24.000000 l
|
||||
16.720367 24.000000 18.680552 24.000000 20.177933 23.237045 c
|
||||
21.495068 22.565931 22.565931 21.495068 23.237045 20.177933 c
|
||||
24.000000 18.680552 24.000000 16.720367 24.000000 12.800000 c
|
||||
24.000000 11.199999 l
|
||||
24.000000 7.279633 24.000000 5.319448 23.237045 3.822067 c
|
||||
22.565931 2.504932 21.495068 1.434069 20.177933 0.762955 c
|
||||
18.680552 0.000000 16.720367 0.000000 12.800000 0.000000 c
|
||||
11.199999 0.000000 l
|
||||
7.279632 0.000000 5.319448 0.000000 3.822066 0.762955 c
|
||||
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
|
||||
0.000000 5.319448 0.000000 7.279633 0.000000 11.200000 c
|
||||
0.000000 12.800001 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
944
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /XObject << /X1 1 0 R >>
|
||||
/ExtGState << /E1 << /SMask << /Type /Mask
|
||||
/G 3 0 R
|
||||
/S /Alpha
|
||||
>>
|
||||
/Type /ExtGState
|
||||
>> >>
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Length 7 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
/E1 gs
|
||||
/X1 Do
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
7 0 obj
|
||||
46
|
||||
endobj
|
||||
|
||||
8 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
|
||||
/Resources 5 0 R
|
||||
/Contents 6 0 R
|
||||
/Parent 9 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
9 0 obj
|
||||
<< /Kids [ 8 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
10 0 obj
|
||||
<< /Pages 9 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 11
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000001152 00000 n
|
||||
0000001174 00000 n
|
||||
0000002366 00000 n
|
||||
0000002388 00000 n
|
||||
0000002686 00000 n
|
||||
0000002788 00000 n
|
||||
0000002809 00000 n
|
||||
0000002982 00000 n
|
||||
0000003056 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 10 0 R
|
||||
/Size 11
|
||||
>>
|
||||
startxref
|
||||
3116
|
||||
%%EOF
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"provides-namespace" : true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
12
submodules/TelegramUI/Images.xcassets/Components/Search Bar/Hashtag.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Components/Search Bar/Hashtag.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "tagsearch_24.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
submodules/TelegramUI/Images.xcassets/Components/Search Bar/Hashtag.imageset/tagsearch_24.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Components/Search Bar/Hashtag.imageset/tagsearch_24.pdf
vendored
Normal file
Binary file not shown.
12
submodules/TelegramUI/Images.xcassets/Premium/Mock.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Premium/Mock.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "mock.png",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
submodules/TelegramUI/Images.xcassets/Premium/Mock.imageset/mock.png
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Premium/Mock.imageset/mock.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.1 KiB |
12
submodules/TelegramUI/Images.xcassets/Premium/Mock2.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Premium/Mock2.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Mock2.png",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
submodules/TelegramUI/Images.xcassets/Premium/Mock2.imageset/Mock2.png
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Premium/Mock2.imageset/Mock2.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 110 KiB |
@ -0,0 +1,241 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import TelegramNotices
|
||||
import ContextUI
|
||||
import AccountContext
|
||||
import ChatMessageItemView
|
||||
import ChatMessageItemCommon
|
||||
import AvatarNode
|
||||
import UndoUI
|
||||
import MessageUI
|
||||
import PeerInfoUI
|
||||
|
||||
extension ChatControllerImpl: MFMessageComposeViewControllerDelegate {
|
||||
func openPhoneContextMenu(number: String, peer: EnginePeer?, message: Message, contentNode: ContextExtractedContentContainingNode, messageNode: ASDisplayNode, frame: CGRect, anyRecognizer: UIGestureRecognizer?, location: CGPoint?) -> Void {
|
||||
if self.presentationInterfaceState.interfaceState.selectionState != nil {
|
||||
return
|
||||
}
|
||||
|
||||
self.dismissAllTooltips()
|
||||
|
||||
let recognizer: TapLongTapOrDoubleTapGestureRecognizer? = anyRecognizer as? TapLongTapOrDoubleTapGestureRecognizer
|
||||
let gesture: ContextGesture? = anyRecognizer as? ContextGesture
|
||||
|
||||
if let messages = self.chatDisplayNode.historyNode.messageGroupInCurrentHistoryView(message.id) {
|
||||
(self.view.window as? WindowHost)?.cancelInteractiveKeyboardGestures()
|
||||
self.chatDisplayNode.cancelInteractiveKeyboardGestures()
|
||||
var updatedMessages = messages
|
||||
for i in 0 ..< updatedMessages.count {
|
||||
if updatedMessages[i].id == message.id {
|
||||
let message = updatedMessages.remove(at: i)
|
||||
updatedMessages.insert(message, at: 0)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
self.chatDisplayNode.messageTransitionNode.dismissMessageReactionContexts()
|
||||
|
||||
let source: ContextContentSource
|
||||
if let location = location {
|
||||
source = .location(ChatMessageContextLocationContentSource(controller: self, location: messageNode.view.convert(messageNode.bounds, to: nil).origin.offsetBy(dx: location.x, dy: location.y)))
|
||||
} else {
|
||||
source = .extracted(ChatMessagePhoneContextExtractedContentSource(chatNode: self.chatDisplayNode, contentNode: contentNode))
|
||||
// source = .extracted(ChatMessageContextExtractedContentSource(chatController: self, chatNode: self.chatDisplayNode, engine: self.context.engine, message: message, selectAll: false))
|
||||
}
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_AddToContacts, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
guard let self, let c else {
|
||||
return
|
||||
}
|
||||
let basicData = DeviceContactBasicData(firstName: "", lastName: "", phoneNumbers: [
|
||||
DeviceContactPhoneNumberData(label: "", value: number)
|
||||
])
|
||||
let contactData = DeviceContactExtendedData(basicData: basicData, middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "")
|
||||
|
||||
pushContactContextOptionsController(context: self.context, contextController: c, presentationData: self.presentationData, peer: nil, contactData: contactData, parentController: self, push: { [weak self] c in
|
||||
self?.push(c)
|
||||
})
|
||||
}))
|
||||
)
|
||||
items.append(.separator)
|
||||
if let peer {
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_SendMessage, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MessageBubble"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.openPeer(peer: peer, navigation: .chat(textInputState: nil, subject: nil, peekData: nil), fromMessage: nil)
|
||||
}))
|
||||
)
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_TelegramVoiceCall, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Call"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.controllerInteraction?.callPeer(peer.id, false)
|
||||
}))
|
||||
)
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_TelegramVideoCall, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/VideoCall"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.controllerInteraction?.callPeer(peer.id, true)
|
||||
}))
|
||||
)
|
||||
} else {
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_InviteToTelegram, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Telegram"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.inviteToTelegram(numbers: [number])
|
||||
}))
|
||||
)
|
||||
}
|
||||
if number.hasPrefix("+888") {
|
||||
|
||||
} else {
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_CallViaCarrier, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/PhoneCall"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.openUrl("tel:\(number)", concealed: false)
|
||||
}))
|
||||
)
|
||||
}
|
||||
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_CopyNumber, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
UIPasteboard.general.string = number
|
||||
|
||||
self.present(UndoOverlayController(presentationData: self.presentationData, content: .copy(text: presentationData.strings.Conversation_PhoneCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
||||
}))
|
||||
)
|
||||
|
||||
items.append(.separator)
|
||||
if let peer {
|
||||
let avatarSize = CGSize(width: 28.0, height: 28.0)
|
||||
let avatarSignal = peerAvatarCompleteImage(account: self.context.account, peer: peer, size: avatarSize)
|
||||
|
||||
let subtitle = NSMutableAttributedString(string: self.presentationData.strings.Chat_Context_Phone_ViewProfile + " >")
|
||||
if let range = subtitle.string.range(of: ">"), let arrowImage = UIImage(bundleImageName: "Item List/InlineTextRightArrow") {
|
||||
subtitle.addAttribute(.attachment, value: arrowImage, range: NSRange(range, in: subtitle.string))
|
||||
subtitle.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: subtitle.string))
|
||||
}
|
||||
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), textLayout: .secondLineWithAttributedValue(subtitle), icon: { theme in return nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: avatarSignal), iconPosition: .left, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.openPeer(peer: peer, navigation: .info(nil), fromMessage: nil)
|
||||
}))
|
||||
)
|
||||
} else {
|
||||
let emptyAction: ((ContextMenuActionItem.Action) -> Void)? = nil
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_NotOnTelegram, textLayout: .multiline, textFont: .small, icon: { _ in return nil }, action: emptyAction))
|
||||
)
|
||||
}
|
||||
|
||||
self.canReadHistory.set(false)
|
||||
|
||||
let controller = ContextController(presentationData: self.presentationData, source: source, items: .single(ContextController.Items(content: .list(items))), recognizer: recognizer, gesture: gesture, disableScreenshots: false)
|
||||
controller.dismissed = { [weak self] in
|
||||
self?.canReadHistory.set(true)
|
||||
}
|
||||
|
||||
self.window?.presentInGlobalOverlay(controller)
|
||||
}
|
||||
}
|
||||
|
||||
private func inviteToTelegram(numbers: [String]) {
|
||||
if MFMessageComposeViewController.canSendText() {
|
||||
let composer = MFMessageComposeViewController()
|
||||
composer.messageComposeDelegate = self
|
||||
composer.recipients = Array(Set(numbers))
|
||||
let url = self.presentationData.strings.InviteText_URL
|
||||
let body = self.presentationData.strings.InviteText_SingleContact(url).string
|
||||
composer.body = body
|
||||
self.messageComposeController = composer
|
||||
if let window = self.view.window {
|
||||
window.rootViewController?.present(composer, animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc public func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
|
||||
self.messageComposeController = nil
|
||||
|
||||
controller.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
private final class ChatMessagePhoneContextExtractedContentSource: ContextExtractedContentSource {
|
||||
let keepInPlace: Bool = false
|
||||
let ignoreContentTouches: Bool = true
|
||||
let blurBackground: Bool = true
|
||||
let adjustContentHorizontally = true
|
||||
|
||||
private weak var chatNode: ChatControllerNode?
|
||||
private let contentNode: ContextExtractedContentContainingNode
|
||||
|
||||
var shouldBeDismissed: Signal<Bool, NoError> {
|
||||
return .single(false)
|
||||
}
|
||||
|
||||
init(chatNode: ChatControllerNode, contentNode: ContextExtractedContentContainingNode) {
|
||||
self.chatNode = chatNode
|
||||
self.contentNode = contentNode
|
||||
}
|
||||
|
||||
func takeView() -> ContextControllerTakeViewInfo? {
|
||||
guard let chatNode = self.chatNode else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
|
||||
transition.updateAlpha(node: self.contentNode.contentNode, alpha: 1.0)
|
||||
|
||||
return ContextControllerTakeViewInfo(containingItem: .node(self.contentNode), contentAreaInScreenSpace: chatNode.convert(chatNode.frameForVisibleArea(), to: nil))
|
||||
}
|
||||
|
||||
func putBack() -> ContextControllerPutBackViewInfo? {
|
||||
guard let chatNode = self.chatNode else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
|
||||
transition.updateAlpha(node: self.contentNode.contentNode, alpha: 0.0, completion: { _ in
|
||||
self.contentNode.removeFromSupernode()
|
||||
})
|
||||
|
||||
return ContextControllerPutBackViewInfo(contentAreaInScreenSpace: chatNode.convert(chatNode.frameForVisibleArea(), to: nil))
|
||||
}
|
||||
}
|
@ -123,6 +123,7 @@ import PeerNameColorScreen
|
||||
import ChatEmptyNode
|
||||
import ChatMediaInputStickerGridItem
|
||||
import AdsInfoScreen
|
||||
import MessageUI
|
||||
|
||||
public enum ChatControllerPeekActions {
|
||||
case standard
|
||||
@ -224,6 +225,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
var validLayout: ContainerViewLayout?
|
||||
|
||||
public weak var parentController: ViewController?
|
||||
public weak var customNavigationController: NavigationController?
|
||||
|
||||
let currentChatListFilter: Int32?
|
||||
let chatNavigationStack: [ChatNavigationStackItem]
|
||||
@ -593,6 +595,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
var networkSpeedEventsDisposable: Disposable?
|
||||
|
||||
var messageComposeController: MFMessageComposeViewController?
|
||||
|
||||
public var alwaysShowSearchResultsAsList: Bool = false {
|
||||
didSet {
|
||||
self.presentationInterfaceState = self.presentationInterfaceState.updatedDisplayHistoryFilterAsList(self.alwaysShowSearchResultsAsList)
|
||||
@ -2295,27 +2299,28 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}
|
||||
}, openUrl: { [weak self] urlData in
|
||||
if let strongSelf = self {
|
||||
let url = urlData.url
|
||||
let concealed = urlData.concealed
|
||||
let message = urlData.message
|
||||
let progress = urlData.progress
|
||||
let forceExternal = urlData.external ?? false
|
||||
|
||||
var skipConcealedAlert = false
|
||||
if let author = message?.author, author.isVerified {
|
||||
skipConcealedAlert = true
|
||||
}
|
||||
|
||||
if let message, let adAttribute = message.attributes.first(where: { $0 is AdMessageAttribute }) as? AdMessageAttribute {
|
||||
strongSelf.chatDisplayNode.historyNode.adMessagesContext?.markAction(opaqueId: adAttribute.opaqueId)
|
||||
}
|
||||
|
||||
if let performOpenURL = strongSelf.performOpenURL {
|
||||
performOpenURL(message, url, progress)
|
||||
} else {
|
||||
strongSelf.openUrl(url, concealed: concealed, forceExternal: forceExternal, skipConcealedAlert: skipConcealedAlert, message: message, allowInlineWebpageResolution: urlData.allowInlineWebpageResolution, progress: progress)
|
||||
}
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let url = urlData.url
|
||||
let concealed = urlData.concealed
|
||||
let message = urlData.message
|
||||
let progress = urlData.progress
|
||||
let forceExternal = urlData.external ?? false
|
||||
|
||||
var skipConcealedAlert = false
|
||||
if let author = message?.author, author.isVerified {
|
||||
skipConcealedAlert = true
|
||||
}
|
||||
|
||||
if let message, let adAttribute = message.attributes.first(where: { $0 is AdMessageAttribute }) as? AdMessageAttribute {
|
||||
strongSelf.chatDisplayNode.historyNode.adMessagesContext?.markAction(opaqueId: adAttribute.opaqueId)
|
||||
}
|
||||
|
||||
if let performOpenURL = strongSelf.performOpenURL {
|
||||
performOpenURL(message, url, progress)
|
||||
} else {
|
||||
strongSelf.openUrl(url, concealed: concealed, forceExternal: forceExternal, skipConcealedAlert: skipConcealedAlert, message: message, allowInlineWebpageResolution: urlData.allowInlineWebpageResolution, progress: progress)
|
||||
}
|
||||
}, shareCurrentLocation: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
@ -4629,6 +4634,34 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return
|
||||
}
|
||||
self.openStickerEditor()
|
||||
}, openPhoneContextMenu: { [weak self] phoneData in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
phoneData.progress?.set(.single(true))
|
||||
let _ = (self.context.engine.peers.resolvePeerByPhone(phone: phoneData.number)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
phoneData.progress?.set(.single(false))
|
||||
|
||||
self.openPhoneContextMenu(number: phoneData.number, peer: peer, message: phoneData.message, contentNode: phoneData.contentNode, messageNode: phoneData.messageNode, frame: phoneData.messageNode.bounds, anyRecognizer: nil, location: nil)
|
||||
})
|
||||
}, openAgeRestrictedMessageMedia: { [weak self] message, reveal in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let controller = chatAgeRestrictionAlertController(context: self.context, updatedPresentationData: self.updatedPresentationData, completion: { [weak self] alwaysShow in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if alwaysShow {
|
||||
self.present(UndoOverlayController(presentationData: self.presentationData, content: .info(title: nil, text: "You can update the visibility of sensitive media in [Data and Storage > Show 18+ Content]().", timeout: nil, customUndoText: nil), elevatedLayout: false, position: .top, action: { _ in return false }), in: .current)
|
||||
}
|
||||
reveal()
|
||||
})
|
||||
self.present(controller, in: .window(.root))
|
||||
}, requestMessageUpdate: { [weak self] id, scroll in
|
||||
if let self {
|
||||
self.chatDisplayNode.historyNode.requestMessageUpdate(id, andScrollToItem: scroll)
|
||||
@ -9511,7 +9544,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
func addPeerContact() {
|
||||
if let peer = self.presentationInterfaceState.renderedPeer?.chatMainPeer as? TelegramUser, let peerStatusSettings = self.presentationInterfaceState.contactStatus?.peerStatusSettings, let contactData = DeviceContactExtendedData(peer: EnginePeer(peer)) {
|
||||
self.present(context.sharedContext.makeDeviceContactInfoController(context: context, subject: .create(peer: peer, contactData: contactData, isSharing: true, shareViaException: peerStatusSettings.contains(.addExceptionWhenAddingContact), completion: { [weak self] peer, stableId, contactData in
|
||||
self.present(context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: self.context), environment: ShareControllerAppEnvironment(sharedContext: self.context.sharedContext), subject: .create(peer: peer, contactData: contactData, isSharing: true, shareViaException: peerStatusSettings.contains(.addExceptionWhenAddingContact), completion: { [weak self] peer, stableId, contactData in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -10556,6 +10589,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
} else if case let .overlay(navigationController) = self.presentationInterfaceState.mode {
|
||||
return navigationController
|
||||
} else {
|
||||
if let navigationController = self.customNavigationController {
|
||||
return navigationController
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import TelegramCallsUI
|
||||
import AutomaticBusinessMessageSetupScreen
|
||||
import MediaEditorScreen
|
||||
import CameraScreen
|
||||
import ShareController
|
||||
|
||||
extension ChatControllerImpl {
|
||||
enum AttachMenuSubject {
|
||||
@ -520,7 +521,7 @@ extension ChatControllerImpl {
|
||||
enqueueMessages.append(.message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: media), threadId: strongSelf.chatLocation.threadId, replyToMessageId: replyMessageSubject?.subjectModel, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
|
||||
strongSelf.sendMessages(strongSelf.transformEnqueueMessages(enqueueMessages, silentPosting: silent, scheduleTime: scheduleTime))
|
||||
} else {
|
||||
let contactController = strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .filter(peer: peerAndContactData.0, contactId: nil, contactData: contactData, completion: { peer, contactData in
|
||||
let contactController = strongSelf.context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: strongSelf.context), environment: ShareControllerAppEnvironment(sharedContext: strongSelf.context.sharedContext), subject: .filter(peer: peerAndContactData.0, contactId: nil, contactData: contactData, completion: { peer, contactData in
|
||||
guard let strongSelf = self, !contactData.basicData.phoneNumbers.isEmpty else {
|
||||
return
|
||||
}
|
||||
@ -1590,7 +1591,7 @@ extension ChatControllerImpl {
|
||||
let message = EnqueueMessage.message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: media), threadId: strongSelf.chatLocation.threadId, replyToMessageId: replyMessageSubject?.subjectModel, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])
|
||||
strongSelf.sendMessages([message])
|
||||
} else {
|
||||
let contactController = strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .filter(peer: peerAndContactData.0, contactId: nil, contactData: contactData, completion: { peer, contactData in
|
||||
let contactController = strongSelf.context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: strongSelf.context), environment: ShareControllerAppEnvironment(sharedContext: strongSelf.context.sharedContext), subject: .filter(peer: peerAndContactData.0, contactId: nil, contactData: contactData, completion: { peer, contactData in
|
||||
guard let strongSelf = self, !contactData.basicData.phoneNumbers.isEmpty else {
|
||||
return
|
||||
}
|
||||
|
@ -176,7 +176,8 @@ extension ChatControllerImpl {
|
||||
}), in: .current)
|
||||
}
|
||||
|
||||
self.push(calendarScreen)
|
||||
self.effectiveNavigationController?.pushViewController(calendarScreen)
|
||||
|
||||
dismissCalendarScreen = { [weak calendarScreen] in
|
||||
calendarScreen?.dismiss(completion: nil)
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import SearchUI
|
||||
import TelegramPermissionsUI
|
||||
import AppBundle
|
||||
import DeviceAccess
|
||||
import ShareController
|
||||
|
||||
public class ComposeControllerImpl: ViewController, ComposeController {
|
||||
private let context: AccountContext
|
||||
@ -200,7 +201,7 @@ public class ComposeControllerImpl: ViewController, ComposeController {
|
||||
switch status {
|
||||
case .allowed:
|
||||
let contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: "", lastName: "", phoneNumbers: [DeviceContactPhoneNumberData(label: "_$!<Mobile>!$_", value: "+")]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "")
|
||||
(strongSelf.navigationController as? NavigationController)?.pushViewController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .create(peer: nil, contactData: contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in
|
||||
(strongSelf.navigationController as? NavigationController)?.pushViewController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: strongSelf.context), environment: ShareControllerAppEnvironment(sharedContext: strongSelf.context.sharedContext), subject: .create(peer: nil, contactData: contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -211,7 +212,7 @@ public class ComposeControllerImpl: ViewController, ComposeController {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(strongSelf.navigationController as? NavigationController)?.replaceAllButRootController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .vcard(nil, stableId, contactData), completed: nil, cancelled: nil), animated: true)
|
||||
(strongSelf.navigationController as? NavigationController)?.replaceAllButRootController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: strongSelf.context), environment: ShareControllerAppEnvironment(sharedContext: strongSelf.context.sharedContext), subject: .vcard(nil, stableId, contactData), completed: nil, cancelled: nil), animated: true)
|
||||
}
|
||||
}), completed: nil, cancelled: nil))
|
||||
case .notDetermined:
|
||||
|
@ -7,6 +7,7 @@ import AccountContext
|
||||
import AlertUI
|
||||
import PresentationDataUtils
|
||||
import PeerInfoUI
|
||||
import ShareController
|
||||
|
||||
func openAddContactImpl(context: AccountContext, firstName: String = "", lastName: String = "", phoneNumber: String, label: String = "_$!<Mobile>!$_", present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, completed: @escaping () -> Void = {}) {
|
||||
let _ = (DeviceAccess.authorizationStatus(subject: .contacts)
|
||||
@ -15,13 +16,13 @@ func openAddContactImpl(context: AccountContext, firstName: String = "", lastNam
|
||||
switch value {
|
||||
case .allowed:
|
||||
let contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: firstName, lastName: lastName, phoneNumbers: [DeviceContactPhoneNumberData(label: label, value: phoneNumber)]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "")
|
||||
present(deviceContactInfoController(context: context, subject: .create(peer: nil, contactData: contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in
|
||||
present(deviceContactInfoController(context: ShareControllerAppAccountContext(context: context), environment: ShareControllerAppEnvironment(sharedContext: context.sharedContext), subject: .create(peer: nil, contactData: contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in
|
||||
if let peer = peer {
|
||||
if let infoController = context.sharedContext.makePeerInfoController(context: context, updatedPresentationData: nil, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) {
|
||||
pushController(infoController)
|
||||
}
|
||||
} else {
|
||||
pushController(deviceContactInfoController(context: context, subject: .vcard(nil, stableId, contactData), completed: nil, cancelled: nil))
|
||||
pushController(deviceContactInfoController(context: ShareControllerAppAccountContext(context: context), environment: ShareControllerAppEnvironment(sharedContext: context.sharedContext), subject: .vcard(nil, stableId, contactData), completed: nil, cancelled: nil))
|
||||
}
|
||||
}), completed: completed, cancelled: nil), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
case .notDetermined:
|
||||
|
@ -330,7 +330,7 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
|
||||
} else {
|
||||
contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: contact.firstName, lastName: contact.lastName, phoneNumbers: [DeviceContactPhoneNumberData(label: "_$!<Mobile>!$_", value: contact.phoneNumber)]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "")
|
||||
}
|
||||
let controller = deviceContactInfoController(context: params.context, updatedPresentationData: params.updatedPresentationData, subject: .vcard(peer?._asPeer(), nil, contactData), completed: nil, cancelled: nil)
|
||||
let controller = deviceContactInfoController(context: ShareControllerAppAccountContext(context: params.context), environment: ShareControllerAppEnvironment(sharedContext: params.context.sharedContext), updatedPresentationData: params.updatedPresentationData, subject: .vcard(peer?._asPeer(), nil, contactData), completed: nil, cancelled: nil)
|
||||
params.navigationController?.pushViewController(controller)
|
||||
})
|
||||
return true
|
||||
|
@ -175,6 +175,8 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
||||
}, openRecommendedChannelContextMenu: { _, _, _ in
|
||||
}, openGroupBoostInfo: { _, _ in
|
||||
}, openStickerEditor: {
|
||||
}, openPhoneContextMenu: { _ in
|
||||
}, openAgeRestrictedMessageMedia: { _, _ in
|
||||
}, requestMessageUpdate: { _, _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, dismissTextInput: {
|
||||
|
@ -1598,8 +1598,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
openResolvedUrlImpl(resolvedUrl, context: context, urlContext: urlContext, navigationController: navigationController, forceExternal: forceExternal, openPeer: openPeer, sendFile: sendFile, sendSticker: sendSticker, sendEmoji: sendEmoji, requestMessageActionUrlAuth: requestMessageActionUrlAuth, joinVoiceChat: joinVoiceChat, present: present, dismissInput: dismissInput, contentContext: contentContext, progress: progress, completion: completion)
|
||||
}
|
||||
|
||||
public func makeDeviceContactInfoController(context: AccountContext, subject: DeviceContactInfoSubject, completed: (() -> Void)?, cancelled: (() -> Void)?) -> ViewController {
|
||||
return deviceContactInfoController(context: context, subject: subject, completed: completed, cancelled: cancelled)
|
||||
public func makeDeviceContactInfoController(context: ShareControllerAccountContext, environment: ShareControllerEnvironment, subject: DeviceContactInfoSubject, completed: (() -> Void)?, cancelled: (() -> Void)?) -> ViewController {
|
||||
return deviceContactInfoController(context: context, environment: environment, subject: subject, completed: completed, cancelled: cancelled)
|
||||
}
|
||||
|
||||
public func makePeersNearbyController(context: AccountContext) -> ViewController {
|
||||
@ -1769,6 +1769,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
}, openRecommendedChannelContextMenu: { _, _, _ in
|
||||
}, openGroupBoostInfo: { _, _ in
|
||||
}, openStickerEditor: {
|
||||
}, openPhoneContextMenu: { _ in
|
||||
}, openAgeRestrictedMessageMedia: { _, _ in
|
||||
}, requestMessageUpdate: { _, _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, dismissTextInput: {
|
||||
|
@ -234,24 +234,22 @@ public struct WebAppParameters {
|
||||
}
|
||||
}
|
||||
|
||||
public func generateWebAppThemeParams(_ presentationTheme: PresentationTheme) -> [String: Any] {
|
||||
let backgroundColor = presentationTheme.list.plainBackgroundColor.rgb
|
||||
let secondaryBackgroundColor = presentationTheme.list.blocksBackgroundColor.rgb
|
||||
public func generateWebAppThemeParams(_ theme: PresentationTheme) -> [String: Any] {
|
||||
return [
|
||||
"bg_color": Int32(bitPattern: backgroundColor),
|
||||
"secondary_bg_color": Int32(bitPattern: secondaryBackgroundColor),
|
||||
"text_color": Int32(bitPattern: presentationTheme.list.itemPrimaryTextColor.rgb),
|
||||
"hint_color": Int32(bitPattern: presentationTheme.list.itemSecondaryTextColor.rgb),
|
||||
"link_color": Int32(bitPattern: presentationTheme.list.itemAccentColor.rgb),
|
||||
"button_color": Int32(bitPattern: presentationTheme.list.itemCheckColors.fillColor.rgb),
|
||||
"button_text_color": Int32(bitPattern: presentationTheme.list.itemCheckColors.foregroundColor.rgb),
|
||||
"header_bg_color": Int32(bitPattern: presentationTheme.rootController.navigationBar.opaqueBackgroundColor.rgb),
|
||||
"accent_text_color": Int32(bitPattern: presentationTheme.list.itemAccentColor.rgb),
|
||||
"section_bg_color": Int32(bitPattern: presentationTheme.list.itemBlocksBackgroundColor.rgb),
|
||||
"section_header_text_color": Int32(bitPattern: presentationTheme.list.freeTextColor.rgb),
|
||||
"subtitle_text_color": Int32(bitPattern: presentationTheme.list.itemSecondaryTextColor.rgb),
|
||||
"destructive_text_color": Int32(bitPattern: presentationTheme.list.itemDestructiveColor.rgb),
|
||||
"section_separator_color": Int32(bitPattern: presentationTheme.list.itemBlocksSeparatorColor.rgb)
|
||||
"bg_color": Int32(bitPattern: theme.list.plainBackgroundColor.rgb),
|
||||
"secondary_bg_color": Int32(bitPattern: theme.list.blocksBackgroundColor.rgb),
|
||||
"text_color": Int32(bitPattern: theme.list.itemPrimaryTextColor.rgb),
|
||||
"hint_color": Int32(bitPattern: theme.list.itemSecondaryTextColor.rgb),
|
||||
"link_color": Int32(bitPattern: theme.list.itemAccentColor.rgb),
|
||||
"button_color": Int32(bitPattern: theme.list.itemCheckColors.fillColor.rgb),
|
||||
"button_text_color": Int32(bitPattern: theme.list.itemCheckColors.foregroundColor.rgb),
|
||||
"header_bg_color": Int32(bitPattern: theme.rootController.navigationBar.opaqueBackgroundColor.rgb),
|
||||
"accent_text_color": Int32(bitPattern: theme.list.itemAccentColor.rgb),
|
||||
"section_bg_color": Int32(bitPattern: theme.list.itemBlocksBackgroundColor.rgb),
|
||||
"section_header_text_color": Int32(bitPattern: theme.list.freeTextColor.rgb),
|
||||
"subtitle_text_color": Int32(bitPattern: theme.list.itemSecondaryTextColor.rgb),
|
||||
"destructive_text_color": Int32(bitPattern: theme.list.itemDestructiveColor.rgb),
|
||||
"section_separator_color": Int32(bitPattern: theme.list.itemBlocksSeparatorColor.rgb)
|
||||
]
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user