mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
Merge commit '55c4015269d5a8fbd4f68bea9c6fb5e41f296b9f'
This commit is contained in:
commit
199bb36dfb
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -7125,3 +7125,9 @@ Sorry for the inconvenience.";
|
||||
"Login.EnterMissingDigits" = "Enter the missing digits";
|
||||
|
||||
"Channel.AdminLogFilter.EventsSentMessages" = "Sent Messages";
|
||||
|
||||
"Contacts.AddContact" = "Add Contact";
|
||||
|
||||
"Conversation.LargeEmojiDisabledInfo" = "You have disabled large emoji, so they appear small and have no effects in chat.";
|
||||
"Conversation.LargeEmojiEnable" = "Enable Large Emoji";
|
||||
"Conversation.LargeEmojiEnabled" = "Large emoji enabled.";
|
||||
|
@ -500,19 +500,24 @@ private final class AuthTransferScanScreenNode: ViewControllerTracingNode, UIScr
|
||||
transition.updateAlpha(node: self.textNode, alpha: controlsAlpha)
|
||||
transition.updateAlpha(node: self.errorTextNode, alpha: controlsAlpha)
|
||||
transition.updateAlpha(node: self.torchButtonNode, alpha: controlsAlpha)
|
||||
for view in self.highlightViews {
|
||||
transition.updateAlpha(layer: view.layer, alpha: controlsAlpha)
|
||||
}
|
||||
|
||||
let titleSize = self.titleNode.updateLayout(CGSize(width: layout.size.width - 16.0, height: layout.size.height))
|
||||
let textSize = self.textNode.updateLayout(CGSize(width: layout.size.width - 16.0, height: layout.size.height))
|
||||
let errorTextSize = self.errorTextNode.updateLayout(CGSize(width: layout.size.width - 16.0, height: layout.size.height))
|
||||
let textFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - textSize.width) / 2.0), y: min(dimHeight - textSize.height - titleSpacing, navigationHeight + floorToScreenPixels((dimHeight - navigationHeight - textSize.height) / 2.0) + 5.0)), size: textSize)
|
||||
var textFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - textSize.width) / 2.0), y: max(dimHeight - textSize.height - titleSpacing, navigationHeight + floorToScreenPixels((dimHeight - navigationHeight - textSize.height) / 2.0) + 5.0)), size: textSize)
|
||||
let titleFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleSize.width) / 2.0), y: textFrame.minY - 18.0 - titleSize.height), size: titleSize)
|
||||
var errorTextFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - errorTextSize.width) / 2.0), y: dimHeight + frameSide + 48.0), size: errorTextSize)
|
||||
errorTextFrame.origin.y += floor(additionalTorchOffset / 2.0)
|
||||
if titleFrame.minY < navigationHeight {
|
||||
transition.updateAlpha(node: self.titleNode, alpha: 0.0)
|
||||
textFrame = textFrame.offsetBy(dx: 0.0, dy: -5.0)
|
||||
} else {
|
||||
transition.updateAlpha(node: self.titleNode, alpha: controlsAlpha)
|
||||
}
|
||||
var errorTextFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - errorTextSize.width) / 2.0), y: dimHeight + frameSide + 48.0), size: errorTextSize)
|
||||
errorTextFrame.origin.y += floor(additionalTorchOffset / 2.0)
|
||||
|
||||
transition.updateFrameAdditive(node: self.titleNode, frame: titleFrame)
|
||||
transition.updateFrameAdditive(node: self.textNode, frame: textFrame)
|
||||
transition.updateFrameAdditive(node: self.errorTextNode, frame: errorTextFrame)
|
||||
|
@ -99,6 +99,8 @@ public final class CallListController: TelegramBaseController {
|
||||
|
||||
super.init(context: context, navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData), mediaAccessoryPanelVisibility: .none, locationBroadcastPanelSource: .none, groupCallPanelSource: .none)
|
||||
|
||||
self.tabBarItemContextActionType = .always
|
||||
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
|
||||
if case .tab = self.mode {
|
||||
@ -394,7 +396,9 @@ public final class CallListController: TelegramBaseController {
|
||||
})
|
||||
}
|
||||
}))
|
||||
(self.navigationController as? NavigationController)?.pushViewController(controller)
|
||||
if let navigationController = self.context.sharedContext.mainWindow?.viewController as? NavigationController {
|
||||
navigationController.pushViewController(controller)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func editPressed() {
|
||||
@ -464,4 +468,43 @@ public final class CallListController: TelegramBaseController {
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
override public func tabBarItemContextAction(sourceNode: ContextExtractedContentContainingNode, gesture: ContextGesture) {
|
||||
var items: [ContextMenuItem] = []
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Calls_StartNewCall, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, f in
|
||||
c.dismiss(completion: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.callPressed()
|
||||
})
|
||||
})))
|
||||
|
||||
let controller = ContextController(account: self.context.account, presentationData: self.presentationData, source: .extracted(CallListTabBarContextExtractedContentSource(controller: self, sourceNode: sourceNode)), items: .single(ContextController.Items(items: items)), recognizer: nil, gesture: gesture)
|
||||
self.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
|
||||
}
|
||||
}
|
||||
|
||||
private final class CallListTabBarContextExtractedContentSource: ContextExtractedContentSource {
|
||||
let keepInPlace: Bool = true
|
||||
let ignoreContentTouches: Bool = true
|
||||
let blurBackground: Bool = true
|
||||
|
||||
private let controller: ViewController
|
||||
private let sourceNode: ContextExtractedContentContainingNode
|
||||
|
||||
init(controller: ViewController, sourceNode: ContextExtractedContentContainingNode) {
|
||||
self.controller = controller
|
||||
self.sourceNode = sourceNode
|
||||
}
|
||||
|
||||
func takeView() -> ContextControllerTakeViewInfo? {
|
||||
return ContextControllerTakeViewInfo(contentContainingNode: self.sourceNode, contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||
}
|
||||
|
||||
func putBack() -> ContextControllerPutBackViewInfo? {
|
||||
return ContextControllerPutBackViewInfo(contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import SearchUI
|
||||
import TelegramPermissionsUI
|
||||
import AppBundle
|
||||
import StickerResources
|
||||
import ContextUI
|
||||
|
||||
private func fixListNodeScrolling(_ listNode: ListView, searchNode: NavigationBarSearchContentNode) -> Bool {
|
||||
if searchNode.expansionProgress > 0.0 && searchNode.expansionProgress < 1.0 {
|
||||
@ -100,6 +101,8 @@ public class ContactsController: ViewController {
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||
|
||||
self.tabBarItemContextActionType = .always
|
||||
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
|
||||
self.title = self.presentationData.strings.Contacts_Title
|
||||
@ -311,11 +314,13 @@ public class ContactsController: ViewController {
|
||||
let presentPeersNearby = {
|
||||
let controller = strongSelf.context.sharedContext.makePeersNearbyController(context: strongSelf.context)
|
||||
controller.navigationPresentation = .master
|
||||
(strongSelf.navigationController as? NavigationController)?.pushViewController(controller, animated: true, completion: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.contactsNode.contactListNode.listNode.clearHighlightAnimated(true)
|
||||
}
|
||||
})
|
||||
if let navigationController = strongSelf.context.sharedContext.mainWindow?.viewController as? NavigationController {
|
||||
navigationController.pushViewController(controller, animated: true, completion: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.contactsNode.contactListNode.listNode.clearHighlightAnimated(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
switch status {
|
||||
@ -332,11 +337,13 @@ public class ContactsController: ViewController {
|
||||
let _ = (strongSelf.navigationController as? NavigationController)?.popViewController(animated: true)
|
||||
}
|
||||
}
|
||||
(strongSelf.navigationController as? NavigationController)?.pushViewController(controller, completion: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.contactsNode.contactListNode.listNode.clearHighlightAnimated(true)
|
||||
}
|
||||
})
|
||||
if let navigationController = strongSelf.context.sharedContext.mainWindow?.viewController as? NavigationController {
|
||||
navigationController.pushViewController(controller, completion: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.contactsNode.contactListNode.listNode.clearHighlightAnimated(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -480,20 +487,26 @@ public class ContactsController: ViewController {
|
||||
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
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if let peer = peer {
|
||||
DispatchQueue.main.async {
|
||||
if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, updatedPresentationData: nil, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) {
|
||||
(strongSelf.navigationController as? NavigationController)?.pushViewController(infoController)
|
||||
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
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if let peer = peer {
|
||||
DispatchQueue.main.async {
|
||||
if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, updatedPresentationData: nil, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) {
|
||||
if let navigationController = strongSelf.context.sharedContext.mainWindow?.viewController as? NavigationController {
|
||||
navigationController.pushViewController(infoController)
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(strongSelf.navigationController as? NavigationController)?.pushViewController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .vcard(nil, stableId, contactData), completed: nil, cancelled: nil))
|
||||
}
|
||||
}), completed: nil, cancelled: nil))
|
||||
}), completed: nil, cancelled: nil))
|
||||
}
|
||||
case .notDetermined:
|
||||
DeviceAccess.authorizeAccess(to: .contacts)
|
||||
default:
|
||||
@ -504,4 +517,54 @@ public class ContactsController: ViewController {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override public func tabBarItemContextAction(sourceNode: ContextExtractedContentContainingNode, gesture: ContextGesture) {
|
||||
var items: [ContextMenuItem] = []
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Contacts_AddContact, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, f in
|
||||
c.dismiss(completion: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.addPressed()
|
||||
})
|
||||
})))
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Contacts_AddPeopleNearby, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Contact List/Context Menu/PeopleNearby"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, f in
|
||||
c.dismiss(completion: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.contactsNode.openPeopleNearby?()
|
||||
})
|
||||
})))
|
||||
|
||||
let controller = ContextController(account: self.context.account, presentationData: self.presentationData, source: .extracted(ContactsTabBarContextExtractedContentSource(controller: self, sourceNode: sourceNode)), items: .single(ContextController.Items(items: items)), recognizer: nil, gesture: gesture)
|
||||
self.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
|
||||
}
|
||||
}
|
||||
|
||||
private final class ContactsTabBarContextExtractedContentSource: ContextExtractedContentSource {
|
||||
let keepInPlace: Bool = true
|
||||
let ignoreContentTouches: Bool = true
|
||||
let blurBackground: Bool = true
|
||||
|
||||
private let controller: ViewController
|
||||
private let sourceNode: ContextExtractedContentContainingNode
|
||||
|
||||
init(controller: ViewController, sourceNode: ContextExtractedContentContainingNode) {
|
||||
self.controller = controller
|
||||
self.sourceNode = sourceNode
|
||||
}
|
||||
|
||||
func takeView() -> ContextControllerTakeViewInfo? {
|
||||
return ContextControllerTakeViewInfo(contentContainingNode: self.sourceNode, contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||
}
|
||||
|
||||
func putBack() -> ContextControllerPutBackViewInfo? {
|
||||
return ContextControllerPutBackViewInfo(contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||
}
|
||||
}
|
||||
|
@ -550,6 +550,7 @@ open class NavigationBar: ASDisplayNode {
|
||||
if self.badgeNode.text != actualText {
|
||||
self.badgeNode.text = actualText
|
||||
self.badgeNode.isHidden = actualText.isEmpty
|
||||
self.backButtonNode.manualAlpha = self.badgeNode.isHidden ? 1.0 : 0.0
|
||||
|
||||
self.invalidateCalculatedLayout()
|
||||
self.requestLayout()
|
||||
@ -835,7 +836,7 @@ open class NavigationBar: ASDisplayNode {
|
||||
self.titleNode.accessibilityTraits = .header
|
||||
|
||||
self.backButtonNode = NavigationButtonNode()
|
||||
self.badgeNode = NavigationBarBadgeNode(fillColor: self.presentationData.theme.badgeBackgroundColor, strokeColor: self.presentationData.theme.badgeStrokeColor, textColor: self.presentationData.theme.badgeTextColor)
|
||||
self.badgeNode = NavigationBarBadgeNode(fillColor: self.presentationData.theme.buttonColor, strokeColor: self.presentationData.theme.buttonColor, textColor: self.presentationData.theme.badgeTextColor)
|
||||
self.badgeNode.isUserInteractionEnabled = false
|
||||
self.badgeNode.isHidden = true
|
||||
self.backButtonArrow = ASImageNode()
|
||||
@ -890,6 +891,7 @@ open class NavigationBar: ASDisplayNode {
|
||||
self.backButtonNode.highlightChanged = { [weak self] index, highlighted in
|
||||
if let strongSelf = self, index == 0 {
|
||||
strongSelf.backButtonArrow.alpha = (highlighted ? 0.4 : 1.0)
|
||||
strongSelf.badgeNode.alpha = (highlighted ? 0.4 : 1.0)
|
||||
}
|
||||
}
|
||||
self.backButtonNode.pressed = { [weak self] index in
|
||||
@ -957,7 +959,7 @@ open class NavigationBar: ASDisplayNode {
|
||||
}
|
||||
self.stripeNode.backgroundColor = self.presentationData.theme.separatorColor
|
||||
|
||||
self.badgeNode.updateTheme(fillColor: self.presentationData.theme.badgeBackgroundColor, strokeColor: self.presentationData.theme.badgeStrokeColor, textColor: self.presentationData.theme.badgeTextColor)
|
||||
self.badgeNode.updateTheme(fillColor: self.presentationData.theme.buttonColor, strokeColor: self.presentationData.theme.buttonColor, textColor: self.presentationData.theme.badgeTextColor)
|
||||
|
||||
self.requestLayout()
|
||||
}
|
||||
@ -1089,7 +1091,7 @@ open class NavigationBar: ASDisplayNode {
|
||||
|
||||
let badgeSize = self.badgeNode.measure(CGSize(width: 200.0, height: 100.0))
|
||||
let backButtonArrowFrame = self.backButtonArrow.frame
|
||||
transition.updateFrame(node: self.badgeNode, frame: CGRect(origin: backButtonArrowFrame.origin.offsetBy(dx: 7.0, dy: -9.0), size: badgeSize))
|
||||
transition.updateFrame(node: self.badgeNode, frame: CGRect(origin: backButtonArrowFrame.origin.offsetBy(dx: 16.0, dy: 2.0), size: badgeSize))
|
||||
|
||||
if self.rightButtonNode.supernode != nil {
|
||||
let rightButtonSize = self.rightButtonNode.updateLayout(constrainedSize: (CGSize(width: size.width, height: nominalHeight)), isLandscape: isLandscape)
|
||||
@ -1122,7 +1124,7 @@ open class NavigationBar: ASDisplayNode {
|
||||
transitionBackArrowNode.alpha = max(0.0, 1.0 - progress * 1.3)
|
||||
|
||||
if let transitionBadgeNode = self.transitionBadgeNode {
|
||||
transitionBadgeNode.frame = CGRect(origin: transitionBackArrowNode.frame.origin.offsetBy(dx: 7.0, dy: -9.0), size: transitionBadgeNode.bounds.size)
|
||||
transitionBadgeNode.frame = CGRect(origin: transitionBackArrowNode.frame.origin.offsetBy(dx: 16.0, dy: 2.0), size: transitionBadgeNode.bounds.size)
|
||||
transitionBadgeNode.alpha = transitionBackArrowNode.alpha
|
||||
}
|
||||
}
|
||||
@ -1284,7 +1286,7 @@ open class NavigationBar: ASDisplayNode {
|
||||
|
||||
public func makeTransitionBadgeNode() -> ASDisplayNode? {
|
||||
if self.badgeNode.supernode != nil && !self.badgeNode.isHidden {
|
||||
let node = NavigationBarBadgeNode(fillColor: self.presentationData.theme.badgeBackgroundColor, strokeColor: self.presentationData.theme.badgeStrokeColor, textColor: self.presentationData.theme.badgeTextColor)
|
||||
let node = NavigationBarBadgeNode(fillColor: self.presentationData.theme.buttonColor, strokeColor: self.presentationData.theme.buttonColor, textColor: self.presentationData.theme.badgeTextColor)
|
||||
node.text = self.badgeNode.text
|
||||
let nodeSize = node.measure(CGSize(width: 200.0, height: 100.0))
|
||||
node.frame = CGRect(origin: CGPoint(), size: nodeSize)
|
||||
|
@ -31,7 +31,7 @@ public final class NavigationBarBadgeNode: ASDisplayNode {
|
||||
self.backgroundNode = ASImageNode()
|
||||
self.backgroundNode.isLayerBacked = true
|
||||
self.backgroundNode.displaysAsynchronously = false
|
||||
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 18.0, color: fillColor, strokeColor: strokeColor, strokeWidth: 1.0)
|
||||
self.backgroundNode.image = generateStretchableFilledCircleImage(radius: 18.0, color: fillColor, backgroundColor: nil)
|
||||
|
||||
super.init()
|
||||
|
||||
@ -43,14 +43,19 @@ public final class NavigationBarBadgeNode: ASDisplayNode {
|
||||
self.fillColor = fillColor
|
||||
self.strokeColor = strokeColor
|
||||
self.textColor = textColor
|
||||
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 18.0, color: fillColor, strokeColor: strokeColor, strokeWidth: 1.0)
|
||||
self.backgroundNode.image = generateStretchableFilledCircleImage(radius: 18.0, color: fillColor, backgroundColor: nil)
|
||||
self.textNode.attributedText = NSAttributedString(string: self.text, font: self.font, textColor: self.textColor)
|
||||
self.textNode.redrawIfPossible()
|
||||
}
|
||||
|
||||
override public func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
|
||||
let badgeSize = self.textNode.updateLayout(constrainedSize)
|
||||
let backgroundSize = CGSize(width: max(18.0, badgeSize.width + 10.0 + 1.0), height: 18.0)
|
||||
let backgroundSize: CGSize
|
||||
if self.text.count < 2 {
|
||||
backgroundSize = CGSize(width: 18.0, height: 18.0)
|
||||
} else {
|
||||
backgroundSize = CGSize(width: max(18.0, badgeSize.width + 10.0 + 1.0), height: 18.0)
|
||||
}
|
||||
let backgroundFrame = CGRect(origin: CGPoint(), size: backgroundSize)
|
||||
self.backgroundNode.frame = backgroundFrame
|
||||
self.textNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels(backgroundFrame.midX - badgeSize.width / 2.0), y: floorToScreenPixels((backgroundFrame.size.height - badgeSize.height) / 2.0)), size: badgeSize)
|
||||
|
@ -278,7 +278,11 @@ private final class NavigationButtonItemNode: ImmediateTextNode {
|
||||
let result = node.view.hitTest(self.view.convert(point, to: node.view), with: event)
|
||||
return result
|
||||
} else {
|
||||
return super.hitTest(point, with: event)
|
||||
let previousAlpha = self.alpha
|
||||
self.alpha = 1.0
|
||||
let result = super.hitTest(point, with: event)
|
||||
self.alpha = previousAlpha
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@ -300,7 +304,9 @@ private final class NavigationButtonItemNode: ImmediateTextNode {
|
||||
}
|
||||
|
||||
if shouldChangeHighlight {
|
||||
self.alpha = !self.isEnabled ? 1.0 : (highlighted ? 0.4 : 1.0)
|
||||
if self.alpha > 0.0 {
|
||||
self.alpha = !self.isEnabled ? 1.0 : (highlighted ? 0.4 : 1.0)
|
||||
}
|
||||
self.highlightChanged(highlighted)
|
||||
}
|
||||
}
|
||||
@ -379,6 +385,14 @@ public final class NavigationButtonNode: ASDisplayNode {
|
||||
return self.nodes.first?.text ?? ""
|
||||
}
|
||||
|
||||
var manualAlpha: CGFloat = 1.0 {
|
||||
didSet {
|
||||
for node in self.nodes {
|
||||
node.alpha = self.manualAlpha
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateManualText(_ text: String, isBack: Bool = true) {
|
||||
let node: NavigationButtonItemNode
|
||||
if self.nodes.count > 0 {
|
||||
@ -404,6 +418,7 @@ public final class NavigationButtonNode: ASDisplayNode {
|
||||
self.nodes.append(node)
|
||||
self.addSubnode(node)
|
||||
}
|
||||
node.alpha = self.manualAlpha
|
||||
node.item = nil
|
||||
node.image = nil
|
||||
node.text = text
|
||||
@ -445,6 +460,7 @@ public final class NavigationButtonNode: ASDisplayNode {
|
||||
self.nodes.append(node)
|
||||
self.addSubnode(node)
|
||||
}
|
||||
node.alpha = self.manualAlpha
|
||||
node.item = items[i]
|
||||
node.image = items[i].image
|
||||
node.text = items[i].title ?? ""
|
||||
|
@ -7,7 +7,11 @@ import SwipeToDismissGesture
|
||||
|
||||
open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDelegate {
|
||||
public var statusBar: StatusBar?
|
||||
public var navigationBar: NavigationBar?
|
||||
public var navigationBar: NavigationBar? {
|
||||
didSet {
|
||||
|
||||
}
|
||||
}
|
||||
public let footerNode: GalleryFooterNode
|
||||
public var currentThumbnailContainerNode: GalleryThumbnailContainerNode?
|
||||
public var overlayNode: ASDisplayNode?
|
||||
@ -137,7 +141,6 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture
|
||||
self.view.addSubview(self.scrollView)
|
||||
|
||||
self.scrollView.addSubview(self.pager.view)
|
||||
self.addSubnode(self.footerNode)
|
||||
|
||||
var previousIndex: Int?
|
||||
self.pager.centralItemIndexOffsetUpdated = { [weak self] itemsIndexAndProgress in
|
||||
@ -256,6 +259,9 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture
|
||||
|
||||
if let navigationBar = self.navigationBar {
|
||||
transition.updateFrame(node: navigationBar, frame: CGRect(origin: CGPoint(x: 0.0, y: self.areControlsHidden ? -navigationBarHeight : 0.0), size: CGSize(width: layout.size.width, height: navigationBarHeight)))
|
||||
if self.footerNode.supernode == nil {
|
||||
self.addSubnode(self.footerNode)
|
||||
}
|
||||
}
|
||||
|
||||
var thumbnailPanelHeight: CGFloat = 0.0
|
||||
|
@ -215,8 +215,6 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
private let recognitionDisposable = MetaDisposable()
|
||||
private var status: MediaResourceStatus?
|
||||
|
||||
private var textCopiedTooltipController: UndoOverlayController?
|
||||
|
||||
private let pagingEnabledPromise = ValuePromise<Bool>(true)
|
||||
|
||||
init(context: AccountContext, presentationData: PresentationData, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void, openActionOptions: @escaping (GalleryControllerInteractionTapAction, Message) -> Void, present: @escaping (ViewController, Any?) -> Void) {
|
||||
@ -260,8 +258,11 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
if let recognizedContentNode = strongSelf.recognizedContentNode {
|
||||
strongSelf.imageNode.isUserInteractionEnabled = active
|
||||
transition.updateAlpha(node: recognizedContentNode, alpha: active ? 1.0 : 0.0)
|
||||
if !active {
|
||||
if active {
|
||||
strongSelf.updateControlsVisibility(false)
|
||||
} else {
|
||||
recognizedContentNode.dismissSelection()
|
||||
strongSelf.updateControlsVisibility(true)
|
||||
}
|
||||
strongSelf.pagingEnabledPromise.set(!active)
|
||||
}
|
||||
@ -333,7 +334,6 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
if let controller = strongSelf.baseNavigationController()?.topViewController as? ViewController {
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with({ $0 })
|
||||
let tooltipController = UndoOverlayController(presentationData: presentationData, content: .copy(text: presentationData.strings.Conversation_TextCopied), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return false })
|
||||
strongSelf.textCopiedTooltipController = tooltipController
|
||||
controller.present(tooltipController, in: .window(.root))
|
||||
}
|
||||
case .share:
|
||||
@ -626,7 +626,19 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
}
|
||||
|
||||
override func animateOut(to node: (ASDisplayNode, CGRect, () -> (UIView?, UIView?)), addToTransitionSurface: (UIView) -> Void, completion: @escaping () -> Void) {
|
||||
self.textCopiedTooltipController?.dismiss()
|
||||
if let controller = self.baseNavigationController()?.topViewController as? ViewController {
|
||||
controller.window?.forEachController({ controller in
|
||||
if let controller = controller as? UndoOverlayController {
|
||||
controller.dismissWithCommitAction()
|
||||
}
|
||||
})
|
||||
controller.forEachController({ controller in
|
||||
if let controller = controller as? UndoOverlayController {
|
||||
controller.dismissWithCommitAction()
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
self.fetchDisposable.set(nil)
|
||||
|
||||
@ -1098,6 +1110,7 @@ private class ImageRecognitionOverlayContentNode: GalleryOverlayContentNode {
|
||||
private let backgroundNode: ASImageNode
|
||||
private let selectedBackgroundNode: ASImageNode
|
||||
private let iconNode: ASImageNode
|
||||
private let selectedIconNode: ASImageNode
|
||||
private let buttonNode: HighlightTrackingButtonNode
|
||||
|
||||
var action: ((Bool) -> Void)?
|
||||
@ -1106,12 +1119,11 @@ private class ImageRecognitionOverlayContentNode: GalleryOverlayContentNode {
|
||||
init(theme: PresentationTheme) {
|
||||
self.backgroundNode = ASImageNode()
|
||||
self.backgroundNode.displaysAsynchronously = false
|
||||
self.backgroundNode.image = generateFilledCircleImage(diameter: 32.0, color: UIColor(white: 0.0, alpha: 0.6))
|
||||
|
||||
|
||||
self.selectedBackgroundNode = ASImageNode()
|
||||
self.selectedBackgroundNode.displaysAsynchronously = false
|
||||
self.selectedBackgroundNode.isHidden = true
|
||||
self.selectedBackgroundNode.image = generateFilledCircleImage(diameter: 32.0, color: theme.list.itemAccentColor)
|
||||
self.selectedBackgroundNode.image = generateFilledCircleImage(diameter: 32.0, color: .white)
|
||||
|
||||
self.buttonNode = HighlightTrackingButtonNode()
|
||||
self.buttonNode.alpha = 0.0
|
||||
@ -1121,6 +1133,12 @@ private class ImageRecognitionOverlayContentNode: GalleryOverlayContentNode {
|
||||
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/LiveTextIcon"), color: .white)
|
||||
self.iconNode.contentMode = .center
|
||||
|
||||
self.selectedIconNode = ASImageNode()
|
||||
self.selectedIconNode.displaysAsynchronously = false
|
||||
self.selectedIconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/LiveTextIcon"), color: .black)
|
||||
self.selectedIconNode.contentMode = .center
|
||||
self.selectedIconNode.isHidden = true
|
||||
|
||||
super.init()
|
||||
|
||||
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
||||
@ -1128,13 +1146,16 @@ private class ImageRecognitionOverlayContentNode: GalleryOverlayContentNode {
|
||||
self.buttonNode.addSubnode(self.backgroundNode)
|
||||
self.buttonNode.addSubnode(self.selectedBackgroundNode)
|
||||
self.buttonNode.addSubnode(self.iconNode)
|
||||
self.buttonNode.addSubnode(self.selectedIconNode)
|
||||
}
|
||||
|
||||
@objc private func buttonPressed() {
|
||||
let newValue = !self.buttonNode.isSelected
|
||||
self.action?(newValue)
|
||||
self.buttonNode.isSelected = newValue
|
||||
self.selectedBackgroundNode.isHidden = !newValue
|
||||
self.selectedIconNode.isHidden = !newValue
|
||||
|
||||
self.action?(newValue)
|
||||
|
||||
if self.interfaceIsHidden && !newValue {
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
|
||||
@ -1159,6 +1180,7 @@ private class ImageRecognitionOverlayContentNode: GalleryOverlayContentNode {
|
||||
self.backgroundNode.frame = CGRect(origin: CGPoint(x: 12.0, y: 12.0), size: buttonSize)
|
||||
self.selectedBackgroundNode.frame = CGRect(origin: CGPoint(x: 12.0, y: 12.0), size: buttonSize)
|
||||
self.iconNode.frame = CGRect(origin: CGPoint(x: 12.0, y: 12.0), size: buttonSize)
|
||||
self.selectedIconNode.frame = CGRect(origin: CGPoint(x: 12.0, y: 12.0), size: buttonSize)
|
||||
|
||||
if self.appeared {
|
||||
if !self.buttonNode.isSelected && isHidden {
|
||||
@ -1168,7 +1190,7 @@ private class ImageRecognitionOverlayContentNode: GalleryOverlayContentNode {
|
||||
}
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.buttonNode, frame: CGRect(x: size.width - rightInset - buttonSize.width - 24.0, y: size.height - bottomInset - buttonSize.height - 24.0, width: buttonSize.width + 24.0, height: buttonSize.height + 24.0))
|
||||
transition.updateFrame(node: self.buttonNode, frame: CGRect(x: size.width - rightInset - buttonSize.width - 24.0, y: 41.0, width: buttonSize.width + 24.0, height: buttonSize.height + 24.0))
|
||||
}
|
||||
|
||||
override func animateIn(previousContentNode: GalleryOverlayContentNode?, transition: ContainedViewLayoutTransition) {
|
||||
|
@ -32,7 +32,7 @@ extension PeerStatusSettings {
|
||||
if (flags & (1 << 8)) != 0 {
|
||||
result.insert(.suggestAddMembers)
|
||||
}
|
||||
self = PeerStatusSettings(flags: result, geoDistance: geoDistance, requestChatTitle: requestChatTitle, requestChatDate: requestChatDate, requestChatIsChannel: (flags & (1 << 9)) != 0)
|
||||
self = PeerStatusSettings(flags: result, geoDistance: geoDistance, requestChatTitle: requestChatTitle, requestChatDate: requestChatDate, requestChatIsChannel: (flags & (1 << 10)) != 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"provides-namespace" : true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"provides-namespace" : true
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "peoplenearbyon_24.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 2.934998 1.735001 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
7.330000 17.464998 m
|
||||
7.330000 18.423212 8.106786 19.199999 9.065001 19.199999 c
|
||||
10.023214 19.199999 10.800000 18.423212 10.800000 17.464998 c
|
||||
10.800000 16.506784 10.023214 15.729999 9.065001 15.729999 c
|
||||
8.106786 15.729999 7.330000 16.506784 7.330000 17.464998 c
|
||||
h
|
||||
9.065001 20.529999 m
|
||||
7.372247 20.529999 6.000000 19.157751 6.000000 17.464998 c
|
||||
6.000000 15.772245 7.372247 14.399999 9.065001 14.399999 c
|
||||
10.757753 14.399999 12.130000 15.772245 12.130000 17.464998 c
|
||||
12.130000 19.157751 10.757753 20.529999 9.065001 20.529999 c
|
||||
h
|
||||
1.330000 3.865000 m
|
||||
1.330000 4.026144 1.400150 4.232668 1.634496 4.483692 c
|
||||
1.872207 4.738321 2.249572 5.004240 2.774642 5.255713 c
|
||||
3.677844 5.688284 4.928888 6.035789 6.400000 6.230032 c
|
||||
6.400001 4.564999 l
|
||||
6.400001 3.755901 7.055903 3.099998 7.865001 3.099998 c
|
||||
10.265000 3.099998 l
|
||||
11.074098 3.099998 11.730000 3.755901 11.730000 4.564999 c
|
||||
11.730000 6.230032 l
|
||||
13.201113 6.035789 14.452158 5.688284 15.355359 5.255713 c
|
||||
15.880429 5.004240 16.257793 4.738321 16.495506 4.483692 c
|
||||
16.729851 4.232668 16.800003 4.026144 16.800003 3.865000 c
|
||||
16.800003 3.677490 16.702744 3.422382 16.359842 3.113541 c
|
||||
16.017097 2.804838 15.483717 2.496361 14.767962 2.223692 c
|
||||
13.341063 1.680111 11.324945 1.330000 9.065001 1.330000 c
|
||||
6.805056 1.330000 4.788938 1.680111 3.362040 2.223692 c
|
||||
2.646284 2.496361 2.112905 2.804838 1.770159 3.113541 c
|
||||
1.427257 3.422382 1.330000 3.677490 1.330000 3.865000 c
|
||||
h
|
||||
2.200152 6.455237 m
|
||||
3.300211 6.982090 4.758119 7.368791 6.400000 7.570784 c
|
||||
6.400000 8.099998 l
|
||||
5.859936 8.099998 l
|
||||
5.076447 8.099998 4.338713 8.757976 4.479389 9.657219 c
|
||||
4.588190 10.352705 4.856467 11.405879 5.540887 12.298394 c
|
||||
6.249626 13.222622 7.373408 13.929998 9.065001 13.929998 c
|
||||
10.756596 13.929998 11.880377 13.222621 12.589115 12.298393 c
|
||||
13.273535 11.405878 13.541812 10.352703 13.650612 9.657217 c
|
||||
13.791287 8.757974 13.053553 8.099998 12.270063 8.099998 c
|
||||
11.730000 8.099998 l
|
||||
11.730000 7.570784 l
|
||||
13.371881 7.368791 14.829790 6.982090 15.929850 6.455237 c
|
||||
16.545578 6.160346 17.079411 5.807216 17.467701 5.391293 c
|
||||
17.859352 4.971766 18.130001 4.456234 18.130001 3.865000 c
|
||||
18.130001 3.168854 17.757156 2.582132 17.249931 2.125290 c
|
||||
16.742554 1.668306 16.045780 1.287239 15.241435 0.980824 c
|
||||
13.628130 0.366230 11.444248 0.000000 9.065001 0.000000 c
|
||||
6.685753 0.000000 4.501871 0.366230 2.888566 0.980824 c
|
||||
2.084221 1.287239 1.387449 1.668306 0.880069 2.125290 c
|
||||
0.372844 2.582132 0.000000 3.168854 0.000000 3.865000 c
|
||||
0.000000 4.456234 0.270649 4.971766 0.662301 5.391293 c
|
||||
1.050590 5.807216 1.584423 6.160346 2.200152 6.455237 c
|
||||
h
|
||||
6.596293 11.489061 m
|
||||
6.105442 10.848969 5.886520 10.046863 5.793407 9.451655 c
|
||||
5.793330 9.451145 l
|
||||
5.800257 9.444448 5.821226 9.429998 5.859936 9.429998 c
|
||||
7.065000 9.429998 l
|
||||
7.432269 9.429998 7.730000 9.132269 7.730000 8.764999 c
|
||||
7.730000 4.564999 l
|
||||
7.730000 4.490440 7.790442 4.429998 7.865001 4.429998 c
|
||||
8.533002 4.429998 l
|
||||
8.533002 6.764999 l
|
||||
8.533002 7.058815 8.771186 7.296999 9.065001 7.296999 c
|
||||
9.358817 7.296999 9.597001 7.058815 9.597001 6.764999 c
|
||||
9.597001 4.429998 l
|
||||
10.265000 4.429998 l
|
||||
10.339560 4.429998 10.400000 4.490440 10.400000 4.564999 c
|
||||
10.400000 8.764999 l
|
||||
10.400000 8.941368 10.470061 9.110514 10.594772 9.235225 c
|
||||
10.719484 9.359937 10.888630 9.429998 11.064999 9.429998 c
|
||||
12.270063 9.429998 l
|
||||
12.308775 9.429998 12.329742 9.444448 12.336671 9.451145 c
|
||||
12.336594 9.451655 l
|
||||
12.243481 10.046862 12.024561 10.848969 11.533709 11.489061 c
|
||||
11.067177 12.097442 10.327614 12.599998 9.065001 12.599998 c
|
||||
7.802389 12.599998 7.062826 12.097442 6.596293 11.489061 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
3674
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000003764 00000 n
|
||||
0000003787 00000 n
|
||||
0000003960 00000 n
|
||||
0000004034 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
4093
|
||||
%%EOF
|
@ -118,7 +118,7 @@ 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:
|
||||
case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy, .largeEmoji:
|
||||
return .waitForSingleTap
|
||||
}
|
||||
}
|
||||
|
@ -3060,6 +3060,31 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
)
|
||||
}
|
||||
})
|
||||
}, openLargeEmojiInfo: { [weak self] _, fitz, file in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: [
|
||||
LargeEmojiActionSheetItem(context: strongSelf.context, text: strongSelf.presentationData.strings.Conversation_LargeEmojiDisabledInfo, fitz: fitz, file: file),
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LargeEmojiEnable, color: .accent, action: { [weak actionSheet, weak self] in
|
||||
actionSheet?.dismissAnimated()
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = updatePresentationThemeSettingsInteractively(accountManager: strongSelf.context.sharedContext.accountManager, { current in
|
||||
return current.withUpdatedLargeEmoji(true)
|
||||
}).start()
|
||||
|
||||
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .emoji(name: "TwoFactorSetupRememberSuccess", text: strongSelf.presentationData.strings.Conversation_LargeEmojiEnabled), elevatedLayout: false, action: { _ in return false }), in: .current)
|
||||
})
|
||||
]), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])])
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
strongSelf.present(actionSheet, in: .window(.root))
|
||||
}, requestMessageUpdate: { [weak self] id in
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(id)
|
||||
|
@ -122,6 +122,7 @@ public final class ChatControllerInteraction {
|
||||
let getMessageTransitionNode: () -> ChatMessageTransitionNode?
|
||||
let updateChoosingSticker: (Bool) -> Void
|
||||
let commitEmojiInteraction: (MessageId, String, EmojiInteraction, TelegramMediaFile) -> Void
|
||||
let openLargeEmojiInfo: (String, String?, TelegramMediaFile) -> Void
|
||||
|
||||
let requestMessageUpdate: (MessageId) -> Void
|
||||
let cancelInteractiveKeyboardGestures: () -> Void
|
||||
@ -218,6 +219,7 @@ public final class ChatControllerInteraction {
|
||||
getMessageTransitionNode: @escaping () -> ChatMessageTransitionNode?,
|
||||
updateChoosingSticker: @escaping (Bool) -> Void,
|
||||
commitEmojiInteraction: @escaping (MessageId, String, EmojiInteraction, TelegramMediaFile) -> Void,
|
||||
openLargeEmojiInfo: @escaping (String, String?, TelegramMediaFile) -> Void,
|
||||
requestMessageUpdate: @escaping (MessageId) -> Void,
|
||||
cancelInteractiveKeyboardGestures: @escaping () -> Void,
|
||||
automaticMediaDownloadSettings: MediaAutoDownloadSettings,
|
||||
@ -300,6 +302,7 @@ public final class ChatControllerInteraction {
|
||||
self.getMessageTransitionNode = getMessageTransitionNode
|
||||
self.updateChoosingSticker = updateChoosingSticker
|
||||
self.commitEmojiInteraction = commitEmojiInteraction
|
||||
self.openLargeEmojiInfo = openLargeEmojiInfo
|
||||
self.requestMessageUpdate = requestMessageUpdate
|
||||
self.cancelInteractiveKeyboardGestures = cancelInteractiveKeyboardGestures
|
||||
|
||||
@ -356,6 +359,7 @@ public final class ChatControllerInteraction {
|
||||
return nil
|
||||
}, updateChoosingSticker: { _ in
|
||||
}, commitEmojiInteraction: { _, _, _, _ in
|
||||
}, openLargeEmojiInfo: { _, _, _ in
|
||||
}, requestMessageUpdate: { _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
||||
|
@ -97,6 +97,7 @@ enum ChatMessageBubbleContentTapAction {
|
||||
case ignore
|
||||
case openPollResults(Data)
|
||||
case copy(String)
|
||||
case largeEmoji(String, String?, TelegramMediaFile)
|
||||
}
|
||||
|
||||
final class ChatMessageBubbleContentItem {
|
||||
|
@ -782,7 +782,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
break
|
||||
case .ignore:
|
||||
return .fail
|
||||
case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy:
|
||||
case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy, .largeEmoji:
|
||||
return .waitForSingleTap
|
||||
}
|
||||
}
|
||||
@ -3098,6 +3098,12 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
item.controllerInteraction.copyText(text)
|
||||
})
|
||||
}
|
||||
case let .largeEmoji(emoji, fitz, file):
|
||||
if let item = self.item {
|
||||
return .optionalAction({
|
||||
item.controllerInteraction.openLargeEmojiInfo(emoji, fitz, file)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -3176,6 +3182,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
break
|
||||
case .copy:
|
||||
break
|
||||
case .largeEmoji:
|
||||
break
|
||||
}
|
||||
}
|
||||
if let tapMessage = tapMessage {
|
||||
|
@ -460,7 +460,23 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
} else if let pre = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Pre)] as? String {
|
||||
return .copy(pre)
|
||||
} else {
|
||||
return .none
|
||||
if let item = self.item, item.message.text.count == 1, !item.presentationData.largeEmoji {
|
||||
let (emoji, fitz) = item.message.text.basicEmoji
|
||||
var emojiFile: TelegramMediaFile?
|
||||
|
||||
emojiFile = item.associatedData.animatedEmojiStickers[emoji]?.first?.file
|
||||
if emojiFile == nil {
|
||||
emojiFile = item.associatedData.animatedEmojiStickers[emoji.strippedEmoji]?.first?.file
|
||||
}
|
||||
|
||||
if let emojiFile = emojiFile {
|
||||
return .largeEmoji(emoji, fitz, emojiFile)
|
||||
} else {
|
||||
return .none
|
||||
}
|
||||
} else {
|
||||
return .none
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let _ = self.statusNode.hitTest(self.view.convert(point, to: self.statusNode.view), with: nil) {
|
||||
|
@ -529,6 +529,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
return nil
|
||||
}, updateChoosingSticker: { _ in
|
||||
}, commitEmojiInteraction: { _, _, _, _ in
|
||||
}, openLargeEmojiInfo: { _, _, _ in
|
||||
}, requestMessageUpdate: { _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,
|
||||
|
@ -89,4 +89,14 @@ final class ChatTextInputMenu {
|
||||
self.state = .general
|
||||
}
|
||||
}
|
||||
|
||||
func hide() {
|
||||
self.back()
|
||||
if #available(iOS 13.0, *) {
|
||||
UIMenuController.shared.hideMenu()
|
||||
} else {
|
||||
UIMenuController.shared.isMenuVisible = false
|
||||
}
|
||||
UIMenuController.shared.update()
|
||||
}
|
||||
}
|
||||
|
@ -2048,8 +2048,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
|
||||
if let textInputNode = self.textInputNode, let presentationInterfaceState = self.presentationInterfaceState {
|
||||
if case .format = self.inputMenu.state {
|
||||
self.inputMenu.deactivate()
|
||||
UIMenuController.shared.update()
|
||||
self.inputMenu.hide()
|
||||
}
|
||||
|
||||
let baseFontSize = max(minInputFontSize, presentationInterfaceState.fontSize.baseDisplaySize)
|
||||
|
@ -155,6 +155,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
||||
return nil
|
||||
}, updateChoosingSticker: { _ in
|
||||
}, commitEmojiInteraction: { _, _, _, _ in
|
||||
}, openLargeEmojiInfo: { _, _, _ in
|
||||
}, requestMessageUpdate: { _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
||||
|
185
submodules/TelegramUI/Sources/LargeEmojiActionSheetItem.swift
Normal file
185
submodules/TelegramUI/Sources/LargeEmojiActionSheetItem.swift
Normal file
@ -0,0 +1,185 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import TelegramUIPreferences
|
||||
import AccountContext
|
||||
import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
import MediaResources
|
||||
import StickerResources
|
||||
import ShimmerEffect
|
||||
|
||||
public final class LargeEmojiActionSheetItem: ActionSheetItem {
|
||||
let context: AccountContext
|
||||
let text: String
|
||||
let fitz: String?
|
||||
let file: TelegramMediaFile
|
||||
|
||||
public init(context: AccountContext, text: String, fitz: String?, file: TelegramMediaFile) {
|
||||
self.context = context
|
||||
self.text = text
|
||||
self.fitz = fitz
|
||||
self.file = file
|
||||
}
|
||||
|
||||
public func node(theme: ActionSheetControllerTheme) -> ActionSheetItemNode {
|
||||
return LargeEmojiActionSheetItemNode(theme: theme, context: self.context, text: self.text, fitz: self.fitz, file: self.file)
|
||||
}
|
||||
|
||||
public func updateNode(_ node: ActionSheetItemNode) {
|
||||
}
|
||||
}
|
||||
|
||||
private final class LargeEmojiActionSheetItemNode: ActionSheetItemNode {
|
||||
private let theme: ActionSheetControllerTheme
|
||||
|
||||
private var placeholderNode: StickerShimmerEffectNode
|
||||
private let imageNode: TransformImageNode
|
||||
private let animationNode: AnimatedStickerNode
|
||||
private let textNode: ImmediateTextNode
|
||||
|
||||
private let accessibilityArea: AccessibilityAreaNode
|
||||
|
||||
private let disposable = MetaDisposable()
|
||||
|
||||
private var setupTimestamp: Double?
|
||||
|
||||
init(theme: ActionSheetControllerTheme, context: AccountContext, text: String, fitz: String?, file: TelegramMediaFile) {
|
||||
self.theme = theme
|
||||
|
||||
let textFont = Font.regular(floor(theme.baseFontSize * 13.0 / 17.0))
|
||||
|
||||
self.placeholderNode = StickerShimmerEffectNode()
|
||||
self.placeholderNode.isUserInteractionEnabled = false
|
||||
|
||||
self.imageNode = TransformImageNode()
|
||||
self.imageNode.displaysAsynchronously = false
|
||||
|
||||
var fitzModifier: EmojiFitzModifier?
|
||||
if let fitz = fitz {
|
||||
fitzModifier = EmojiFitzModifier(emoji: fitz)
|
||||
}
|
||||
self.animationNode = AnimatedStickerNode()
|
||||
self.animationNode.setup(source: AnimatedStickerResourceSource(account: context.account, resource: file.resource, fitzModifier: fitzModifier), width: 192, height: 192, playbackMode: .once, mode: .direct(cachePathPrefix: nil))
|
||||
self.animationNode.visibility = true
|
||||
|
||||
self.textNode = ImmediateTextNode()
|
||||
self.textNode.displaysAsynchronously = false
|
||||
self.textNode.maximumNumberOfLines = 0
|
||||
self.textNode.textAlignment = .center
|
||||
self.textNode.isAccessibilityElement = false
|
||||
|
||||
self.accessibilityArea = AccessibilityAreaNode()
|
||||
|
||||
super.init(theme: theme)
|
||||
|
||||
self.hasSeparator = true
|
||||
|
||||
self.addSubnode(self.imageNode)
|
||||
self.addSubnode(self.placeholderNode)
|
||||
self.addSubnode(self.animationNode)
|
||||
self.addSubnode(self.textNode)
|
||||
self.addSubnode(self.accessibilityArea)
|
||||
|
||||
let attributedText = NSAttributedString(string: text, font: textFont, textColor: theme.secondaryTextColor)
|
||||
self.textNode.attributedText = attributedText
|
||||
|
||||
self.accessibilityArea.accessibilityLabel = attributedText.string
|
||||
self.accessibilityArea.accessibilityTraits = .staticText
|
||||
|
||||
let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512)
|
||||
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: context.account.postbox, file: file, small: false, size: dimensions.cgSize.aspectFilled(CGSize(width: 384.0, height: 384.0)), fitzModifier: fitzModifier, thumbnail: false, synchronousLoad: true), attemptSynchronously: true)
|
||||
self.disposable.set(freeMediaFileInteractiveFetched(account: context.account, fileReference: .standalone(media: file)).start())
|
||||
|
||||
self.setupTimestamp = CACurrentMediaTime()
|
||||
|
||||
self.animationNode.started = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.imageNode.alpha = 0.0
|
||||
|
||||
let current = CACurrentMediaTime()
|
||||
if let setupTimestamp = strongSelf.setupTimestamp, current - setupTimestamp > 0.3 {
|
||||
if !strongSelf.placeholderNode.alpha.isZero {
|
||||
strongSelf.animationNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
strongSelf.removePlaceholder(animated: true)
|
||||
}
|
||||
} else {
|
||||
strongSelf.removePlaceholder(animated: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var firstTime = true
|
||||
self.imageNode.imageUpdated = { [weak self] image in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if image != nil {
|
||||
if firstTime && !strongSelf.placeholderNode.isEmpty {
|
||||
strongSelf.imageNode.alpha = 0.0
|
||||
} else {
|
||||
if strongSelf.setupTimestamp == nil {
|
||||
strongSelf.removePlaceholder(animated: true)
|
||||
}
|
||||
}
|
||||
firstTime = false
|
||||
}
|
||||
}
|
||||
|
||||
if let immediateThumbnailData = file.immediateThumbnailData {
|
||||
self.placeholderNode.update(backgroundColor: nil, foregroundColor: theme.secondaryTextColor.blitOver(theme.itemBackgroundColor, alpha: 0.55), shimmeringColor: theme.itemBackgroundColor.withAlphaComponent(0.4), data: immediateThumbnailData, size: CGSize(width: 96.0, height: 96.0), imageSize: dimensions.cgSize)
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.animationNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tap)))
|
||||
}
|
||||
|
||||
@objc private func tap() {
|
||||
let _ = self.animationNode.playIfNeeded()
|
||||
}
|
||||
|
||||
private func removePlaceholder(animated: Bool) {
|
||||
self.placeholderNode.alpha = 0.0
|
||||
if !animated {
|
||||
self.placeholderNode.removeFromSupernode()
|
||||
} else {
|
||||
self.placeholderNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in
|
||||
self?.placeholderNode.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public override func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||
let textSize = self.textNode.updateLayout(CGSize(width: constrainedSize.width - 120.0, height: .greatestFiniteMagnitude))
|
||||
|
||||
let topInset: CGFloat = 26.0
|
||||
let textSpacing: CGFloat = 17.0
|
||||
let bottomInset: CGFloat = 15.0
|
||||
|
||||
let iconSize = CGSize(width: 96.0, height: 96.0)
|
||||
self.animationNode.frame = CGRect(origin: CGPoint(x: floor((constrainedSize.width - iconSize.width) / 2.0), y: topInset), size: iconSize)
|
||||
self.animationNode.updateLayout(size: iconSize)
|
||||
self.placeholderNode.frame = self.animationNode.frame
|
||||
|
||||
self.textNode.frame = CGRect(origin: CGPoint(x: floor((constrainedSize.width - textSize.width) / 2.0), y: topInset + iconSize.height + textSpacing), size: textSize)
|
||||
|
||||
let size = CGSize(width: constrainedSize.width, height: topInset + iconSize.height + textSpacing + textSize.height + bottomInset)
|
||||
self.accessibilityArea.frame = CGRect(origin: CGPoint(), size: size)
|
||||
|
||||
self.placeholderNode.updateAbsoluteRect(CGRect(origin: CGPoint(x: self.placeholderNode.frame.minX, y: self.placeholderNode.frame.minY), size: self.placeholderNode.frame.size), within: size)
|
||||
|
||||
self.updateInternalLayout(size, constrainedSize: constrainedSize)
|
||||
return size
|
||||
}
|
||||
}
|
@ -147,6 +147,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
||||
return nil
|
||||
}, updateChoosingSticker: { _ in
|
||||
}, commitEmojiInteraction: { _, _, _, _ in
|
||||
}, openLargeEmojiInfo: { _, _, _ in
|
||||
}, requestMessageUpdate: { _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false), presentationContext: ChatPresentationContext(backgroundNode: nil))
|
||||
|
@ -52,6 +52,22 @@ final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem {
|
||||
}
|
||||
}
|
||||
|
||||
private func generateExpandBackground(size: CGSize, color: UIColor) -> UIImage? {
|
||||
return generateImage(size, rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
var locations: [CGFloat] = [0.0, 1.0]
|
||||
let colors: [CGColor] = [color.withAlphaComponent(0.0).cgColor, color.cgColor]
|
||||
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
|
||||
|
||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 40.0, y: size.height), options: CGGradientDrawingOptions())
|
||||
context.setFillColor(color.cgColor)
|
||||
context.fill(CGRect(origin: CGPoint(x: 40.0, y: 0.0), size: CGSize(width: size.width - 40.0, height: size.height)))
|
||||
})
|
||||
}
|
||||
|
||||
private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
||||
private let selectionNode: PeerInfoScreenSelectableBackgroundNode
|
||||
private let maskNode: ASImageNode
|
||||
@ -59,6 +75,7 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
||||
private let textNode: ImmediateTextNode
|
||||
private let bottomSeparatorNode: ASDisplayNode
|
||||
|
||||
private let expandBackgroundNode: ASImageNode
|
||||
private let expandNode: ImmediateTextNode
|
||||
private let expandButonNode: HighlightTrackingButtonNode
|
||||
|
||||
@ -90,6 +107,9 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
||||
self.bottomSeparatorNode = ASDisplayNode()
|
||||
self.bottomSeparatorNode.isLayerBacked = true
|
||||
|
||||
self.expandBackgroundNode = ASImageNode()
|
||||
self.expandBackgroundNode.displaysAsynchronously = false
|
||||
|
||||
self.expandNode = ImmediateTextNode()
|
||||
self.expandNode.displaysAsynchronously = false
|
||||
self.expandNode.isUserInteractionEnabled = false
|
||||
@ -110,6 +130,7 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
||||
self.addSubnode(self.labelNode)
|
||||
self.addSubnode(self.textNode)
|
||||
|
||||
self.addSubnode(self.expandBackgroundNode)
|
||||
self.addSubnode(self.expandNode)
|
||||
self.addSubnode(self.expandButonNode)
|
||||
|
||||
@ -211,7 +232,7 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
||||
textColorValue = presentationData.theme.list.itemAccentColor
|
||||
}
|
||||
|
||||
self.expandNode.attributedText = NSAttributedString(string: presentationData.strings.PeerInfo_BioExpand, font: Font.regular(17.0), textColor: presentationData.theme.list.itemAccentColor)
|
||||
self.expandNode.attributedText = NSAttributedString(string: presentationData.strings.PeerInfo_BioExpand.uppercased(), font: Font.medium(16.0), textColor: presentationData.theme.list.itemAccentColor)
|
||||
let expandSize = self.expandNode.updateLayout(CGSize(width: width, height: 100.0))
|
||||
|
||||
self.labelNode.attributedText = NSAttributedString(string: item.label, font: Font.regular(14.0), textColor: presentationData.theme.list.itemPrimaryTextColor)
|
||||
@ -223,7 +244,7 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
||||
self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(17.0), textColor: textColorValue)
|
||||
case let .multiLine(maxLines, enabledEntities):
|
||||
self.textNode.maximumNumberOfLines = self.isExpanded ? maxLines : 3
|
||||
self.textNode.cutout = self.isExpanded ? nil : TextNodeCutout(bottomRight: CGSize(width: expandSize.width + 4.0, height: expandSize.height))
|
||||
// self.textNode.cutout = self.isExpanded ? nil : TextNodeCutout(bottomRight: CGSize(width: expandSize.width + 4.0, height: expandSize.height))
|
||||
if enabledEntities.isEmpty {
|
||||
self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(17.0), textColor: textColorValue)
|
||||
} else {
|
||||
@ -246,9 +267,11 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
||||
let textSize = textLayout.size
|
||||
|
||||
if case .multiLine = item.textBehavior, textLayout.truncated, !self.isExpanded {
|
||||
self.expandBackgroundNode.isHidden = false
|
||||
self.expandNode.isHidden = false
|
||||
self.expandButonNode.isHidden = false
|
||||
} else {
|
||||
self.expandBackgroundNode.isHidden = true
|
||||
self.expandNode.isHidden = true
|
||||
self.expandButonNode.isHidden = true
|
||||
}
|
||||
@ -260,6 +283,12 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
||||
self.expandNode.frame = expandFrame
|
||||
self.expandButonNode.frame = expandFrame.insetBy(dx: -8.0, dy: -8.0)
|
||||
|
||||
var expandBackgroundFrame = expandFrame
|
||||
expandBackgroundFrame.origin.x -= 50.0
|
||||
expandBackgroundFrame.size.width += 50.0
|
||||
self.expandBackgroundNode.frame = expandBackgroundFrame
|
||||
self.expandBackgroundNode.image = generateExpandBackground(size: expandBackgroundFrame.size, color: presentationData.theme.list.itemBlocksBackgroundColor)
|
||||
|
||||
transition.updateFrame(node: self.labelNode, frame: labelFrame)
|
||||
transition.updateFrame(node: self.textNode, frame: textFrame)
|
||||
|
||||
|
@ -2151,6 +2151,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
return nil
|
||||
}, updateChoosingSticker: { _ in
|
||||
}, commitEmojiInteraction: { _, _, _, _ in
|
||||
}, openLargeEmojiInfo: { _, _, _ in
|
||||
}, requestMessageUpdate: { _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
||||
|
@ -829,8 +829,7 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, TGCaptionPanelView, A
|
||||
|
||||
if let textInputNode = self.textInputNode, let presentationInterfaceState = self.presentationInterfaceState {
|
||||
if case .format = self.inputMenu.state {
|
||||
self.inputMenu.deactivate()
|
||||
UIMenuController.shared.update()
|
||||
self.inputMenu.hide()
|
||||
}
|
||||
|
||||
let baseFontSize = max(minInputFontSize, presentationInterfaceState.fontSize.baseDisplaySize)
|
||||
|
@ -1292,6 +1292,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
return nil
|
||||
}, updateChoosingSticker: { _ in
|
||||
}, commitEmojiInteraction: { _, _, _, _ in
|
||||
}, openLargeEmojiInfo: { _, _, _ in
|
||||
}, requestMessageUpdate: { _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
||||
|
Loading…
x
Reference in New Issue
Block a user