Merge commit '55c4015269d5a8fbd4f68bea9c6fb5e41f296b9f'

This commit is contained in:
Ali 2021-11-30 22:18:24 +04:00
commit 199bb36dfb
33 changed files with 676 additions and 61 deletions

View File

@ -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.";

View File

@ -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)

View File

@ -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)
}
}

View File

@ -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,12 +314,14 @@ 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 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 {
case .allowed:
@ -332,12 +337,14 @@ public class ContactsController: ViewController {
let _ = (strongSelf.navigationController as? NavigationController)?.popViewController(animated: true)
}
}
(strongSelf.navigationController as? NavigationController)?.pushViewController(controller, completion: { [weak self] in
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
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) {
(strongSelf.navigationController as? NavigationController)?.pushViewController(infoController)
if let navigationController = strongSelf.context.sharedContext.mainWindow?.viewController as? NavigationController {
navigationController.pushViewController(infoController)
}
}
}
} else {
(strongSelf.navigationController as? NavigationController)?.pushViewController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .vcard(nil, stableId, contactData), completed: nil, cancelled: nil))
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))
}
}
}), 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)
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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 {
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 ?? ""

View File

@ -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

View File

@ -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) {

View File

@ -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)
}
}
}

View File

@ -1,7 +1,7 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
},
"properties" : {
"provides-namespace" : true

View File

@ -0,0 +1,9 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"provides-namespace" : true
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "peoplenearbyon_24.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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)

View File

@ -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,

View File

@ -97,6 +97,7 @@ enum ChatMessageBubbleContentTapAction {
case ignore
case openPollResults(Data)
case copy(String)
case largeEmoji(String, String?, TelegramMediaFile)
}
final class ChatMessageBubbleContentItem {

View File

@ -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 {

View File

@ -459,9 +459,25 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
return .bankCard(bankCard)
} else if let pre = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Pre)] as? String {
return .copy(pre)
} else {
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) {
return .ignore

View File

@ -529,6 +529,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
return nil
}, updateChoosingSticker: { _ in
}, commitEmojiInteraction: { _, _, _, _ in
}, openLargeEmojiInfo: { _, _, _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,

View File

@ -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()
}
}

View File

@ -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)

View File

@ -155,6 +155,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
return nil
}, updateChoosingSticker: { _ in
}, commitEmojiInteraction: { _, _, _, _ in
}, openLargeEmojiInfo: { _, _, _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View 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
}
}

View File

@ -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))

View File

@ -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)

View File

@ -2151,6 +2151,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
return nil
}, updateChoosingSticker: { _ in
}, commitEmojiInteraction: { _, _, _, _ in
}, openLargeEmojiInfo: { _, _, _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -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)

View File

@ -1292,6 +1292,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
return nil
}, updateChoosingSticker: { _ in
}, commitEmojiInteraction: { _, _, _, _ in
}, openLargeEmojiInfo: { _, _, _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,