mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Attachment menu improvements
This commit is contained in:
parent
5e84216346
commit
ec8702ed07
BIN
Telegram/Telegram-iOS/Resources/Banned.tgs
Normal file
BIN
Telegram/Telegram-iOS/Resources/Banned.tgs
Normal file
Binary file not shown.
BIN
Telegram/Telegram-iOS/Resources/Location.tgs
Normal file
BIN
Telegram/Telegram-iOS/Resources/Location.tgs
Normal file
Binary file not shown.
BIN
Telegram/Telegram-iOS/Resources/Photos.tgs
Normal file
BIN
Telegram/Telegram-iOS/Resources/Photos.tgs
Normal file
Binary file not shown.
@ -7328,3 +7328,6 @@ Sorry for the inconvenience.";
|
|||||||
"Attachment.DeselectedItems_0" = "%@ items deselected";
|
"Attachment.DeselectedItems_0" = "%@ items deselected";
|
||||||
|
|
||||||
"PrivacyPhoneNumberSettings.CustomPublicLink" = "Users who have your number saved in their contacts will also see it on Telegram.\n\nThis public link opens a chat with you:\n[https://t.me/%@]()";
|
"PrivacyPhoneNumberSettings.CustomPublicLink" = "Users who have your number saved in their contacts will also see it on Telegram.\n\nThis public link opens a chat with you:\n[https://t.me/%@]()";
|
||||||
|
|
||||||
|
"Attachment.MyAlbums" = "My Albums";
|
||||||
|
"Attachment.MediaTypes" = "Media Types";
|
||||||
|
@ -3,7 +3,7 @@ import Display
|
|||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
|
|
||||||
public protocol ContactSelectionController: ViewController {
|
public protocol ContactSelectionController: ViewController {
|
||||||
var result: Signal<([ContactListPeer], ContactListAction, Bool, Int32?)?, NoError> { get }
|
var result: Signal<([ContactListPeer], ContactListAction, Bool, Int32?, NSAttributedString?)?, NoError> { get }
|
||||||
var displayProgress: Bool { get set }
|
var displayProgress: Bool { get set }
|
||||||
var dismissed: (() -> Void)? { get set }
|
var dismissed: (() -> Void)? { get set }
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@ import DirectionalPanGesture
|
|||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import MapKit
|
import MapKit
|
||||||
|
|
||||||
|
private let overflowInset: CGFloat = 70.0
|
||||||
|
|
||||||
final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
|
final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||||
let wrappingNode: ASDisplayNode
|
let wrappingNode: ASDisplayNode
|
||||||
let clipNode: ASDisplayNode
|
let clipNode: ASDisplayNode
|
||||||
@ -18,6 +20,7 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
var isReadyUpdated: (() -> Void)?
|
var isReadyUpdated: (() -> Void)?
|
||||||
var updateDismissProgress: ((CGFloat, ContainedViewLayoutTransition) -> Void)?
|
var updateDismissProgress: ((CGFloat, ContainedViewLayoutTransition) -> Void)?
|
||||||
var interactivelyDismissed: (() -> Void)?
|
var interactivelyDismissed: (() -> Void)?
|
||||||
|
var controllerRemoved: ((ViewController) -> Void)?
|
||||||
|
|
||||||
var updateModalProgress: ((CGFloat, ContainedViewLayoutTransition) -> Void)?
|
var updateModalProgress: ((CGFloat, ContainedViewLayoutTransition) -> Void)?
|
||||||
|
|
||||||
@ -49,8 +52,12 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
self.wrappingNode = ASDisplayNode()
|
self.wrappingNode = ASDisplayNode()
|
||||||
self.clipNode = ASDisplayNode()
|
self.clipNode = ASDisplayNode()
|
||||||
|
|
||||||
self.container = NavigationContainer(controllerRemoved: { _ in })
|
var controllerRemovedImpl: ((ViewController) -> Void)?
|
||||||
|
self.container = NavigationContainer(controllerRemoved: { c in
|
||||||
|
controllerRemovedImpl?(c)
|
||||||
|
})
|
||||||
self.container.clipsToBounds = true
|
self.container.clipsToBounds = true
|
||||||
|
self.container.overflowInset = overflowInset
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
@ -72,12 +79,16 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
applySmoothRoundedCorners(self.container.layer)
|
applySmoothRoundedCorners(self.container.layer)
|
||||||
|
|
||||||
|
controllerRemovedImpl = { [weak self] c in
|
||||||
|
self?.controllerRemoved?(c)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didLoad() {
|
override func didLoad() {
|
||||||
super.didLoad()
|
super.didLoad()
|
||||||
|
|
||||||
let panRecognizer = DirectionalPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))
|
let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))
|
||||||
panRecognizer.delegate = self
|
panRecognizer.delegate = self
|
||||||
panRecognizer.delaysTouchesBegan = false
|
panRecognizer.delaysTouchesBegan = false
|
||||||
panRecognizer.cancelsTouchesInView = true
|
panRecognizer.cancelsTouchesInView = true
|
||||||
@ -85,11 +96,23 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
self.wrappingNode.view.addGestureRecognizer(panRecognizer)
|
self.wrappingNode.view.addGestureRecognizer(panRecognizer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||||
|
if let (layout, _, _) = self.validLayout {
|
||||||
|
if case .regular = layout.metrics.widthClass {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||||
if gestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer is UIPanGestureRecognizer {
|
if gestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer is UIPanGestureRecognizer {
|
||||||
if let _ = otherGestureRecognizer.view?.superview as? MKMapView {
|
if let _ = otherGestureRecognizer.view?.superview as? MKMapView {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if let _ = otherGestureRecognizer.view?.asyncdisplaykit_node as? CollectionIndexNode {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -102,7 +125,11 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
return 210.0
|
return 210.0
|
||||||
}
|
}
|
||||||
if case .compact = layout.metrics.widthClass {
|
if case .compact = layout.metrics.widthClass {
|
||||||
return max(layout.size.width, layout.size.height) * 0.2488
|
var factor: CGFloat = 0.2488
|
||||||
|
if layout.size.width <= 320.0 {
|
||||||
|
factor = 0.15
|
||||||
|
}
|
||||||
|
return floor(max(layout.size.width, layout.size.height) * factor)
|
||||||
} else {
|
} else {
|
||||||
return 210.0
|
return 210.0
|
||||||
}
|
}
|
||||||
@ -165,7 +192,6 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
|
|
||||||
self.panGestureArguments = (topInset, translation, scrollView, listNode)
|
self.panGestureArguments = (topInset, translation, scrollView, listNode)
|
||||||
|
|
||||||
|
|
||||||
if !self.isExpanded {
|
if !self.isExpanded {
|
||||||
if currentOffset > 0.0, let scrollView = scrollView {
|
if currentOffset > 0.0, let scrollView = scrollView {
|
||||||
scrollView.panGestureRecognizer.setTranslation(CGPoint(), in: scrollView)
|
scrollView.panGestureRecognizer.setTranslation(CGPoint(), in: scrollView)
|
||||||
@ -306,15 +332,20 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
let isLandscape = layout.orientation == .landscape
|
let isLandscape = layout.orientation == .landscape
|
||||||
let edgeTopInset = isLandscape ? 0.0 : defaultTopInset
|
let edgeTopInset = isLandscape ? 0.0 : defaultTopInset
|
||||||
|
|
||||||
|
var effectiveExpanded = self.isExpanded
|
||||||
|
if case .regular = layout.metrics.widthClass {
|
||||||
|
effectiveExpanded = true
|
||||||
|
}
|
||||||
|
|
||||||
let topInset: CGFloat
|
let topInset: CGFloat
|
||||||
if let (panInitialTopInset, panOffset, _, _) = self.panGestureArguments {
|
if let (panInitialTopInset, panOffset, _, _) = self.panGestureArguments {
|
||||||
if self.isExpanded {
|
if effectiveExpanded {
|
||||||
topInset = min(edgeTopInset, panInitialTopInset + max(0.0, panOffset))
|
topInset = min(edgeTopInset, panInitialTopInset + max(0.0, panOffset))
|
||||||
} else {
|
} else {
|
||||||
topInset = max(0.0, panInitialTopInset + min(0.0, panOffset))
|
topInset = max(0.0, panInitialTopInset + min(0.0, panOffset))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
topInset = self.isExpanded ? 0.0 : edgeTopInset
|
topInset = effectiveExpanded ? 0.0 : edgeTopInset
|
||||||
}
|
}
|
||||||
transition.updateFrame(node: self.wrappingNode, frame: CGRect(origin: CGPoint(x: 0.0, y: topInset), size: layout.size))
|
transition.updateFrame(node: self.wrappingNode, frame: CGRect(origin: CGPoint(x: 0.0, y: topInset), size: layout.size))
|
||||||
|
|
||||||
@ -359,7 +390,6 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
|
|
||||||
let effectiveStatusBarHeight: CGFloat? = nil
|
let effectiveStatusBarHeight: CGFloat? = nil
|
||||||
|
|
||||||
let overflowInset: CGFloat = 70.0
|
|
||||||
var safeInsets = layout.safeInsets
|
var safeInsets = layout.safeInsets
|
||||||
safeInsets.left += overflowInset
|
safeInsets.left += overflowInset
|
||||||
safeInsets.right += overflowInset
|
safeInsets.right += overflowInset
|
||||||
@ -379,29 +409,12 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
clipFrame = CGRect(x: containerFrame.minX + overflowInset, y: containerFrame.minY, width: containerFrame.width - overflowInset * 2.0, height: containerFrame.height)
|
clipFrame = CGRect(x: containerFrame.minX + overflowInset, y: containerFrame.minY, width: containerFrame.width - overflowInset * 2.0, height: containerFrame.height)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.clipNode.clipsToBounds = true
|
containerLayout = ContainerViewLayout(size: layout.size, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), additionalInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: layout.inVoiceOver)
|
||||||
self.clipNode.cornerRadius = 10.0
|
|
||||||
if #available(iOS 11.0, *) {
|
|
||||||
self.clipNode.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner]
|
|
||||||
}
|
|
||||||
|
|
||||||
let verticalInset: CGFloat = 44.0
|
let unscaledFrame = CGRect(origin: CGPoint(), size: containerLayout.size)
|
||||||
|
|
||||||
let maxSide = max(layout.size.width, layout.size.height)
|
|
||||||
let minSide = min(layout.size.width, layout.size.height)
|
|
||||||
let containerSize = CGSize(width: min(layout.size.width - 20.0, floor(maxSide / 2.0)), height: min(layout.size.height, minSide) - verticalInset * 2.0)
|
|
||||||
containerFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - containerSize.width) / 2.0), y: floor((layout.size.height - containerSize.height) / 2.0)), size: containerSize)
|
|
||||||
containerScale = 1.0
|
containerScale = 1.0
|
||||||
clipFrame = containerFrame
|
containerFrame = unscaledFrame
|
||||||
|
clipFrame = unscaledFrame
|
||||||
var inputHeight: CGFloat?
|
|
||||||
if let inputHeightValue = layout.inputHeight {
|
|
||||||
inputHeight = max(0.0, inputHeightValue - (layout.size.height - containerFrame.maxY))
|
|
||||||
}
|
|
||||||
|
|
||||||
let effectiveStatusBarHeight: CGFloat? = nil
|
|
||||||
|
|
||||||
containerLayout = ContainerViewLayout(size: containerSize, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), additionalInsets: UIEdgeInsets(), statusBarHeight: effectiveStatusBarHeight, inputHeight: inputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver)
|
|
||||||
}
|
}
|
||||||
transition.updateFrameAsPositionAndBounds(node: self.clipNode, frame: clipFrame)
|
transition.updateFrameAsPositionAndBounds(node: self.clipNode, frame: clipFrame)
|
||||||
transition.updateFrameAsPositionAndBounds(node: self.container, frame: CGRect(origin: CGPoint(x: containerFrame.minX, y: 0.0), size: containerFrame.size))
|
transition.updateFrameAsPositionAndBounds(node: self.container, frame: CGRect(origin: CGPoint(x: containerFrame.minX, y: 0.0), size: containerFrame.size))
|
||||||
|
@ -22,6 +22,8 @@ public enum AttachmentButtonType: Equatable {
|
|||||||
|
|
||||||
public protocol AttachmentContainable: ViewController {
|
public protocol AttachmentContainable: ViewController {
|
||||||
var requestAttachmentMenuExpansion: () -> Void { get set }
|
var requestAttachmentMenuExpansion: () -> Void { get set }
|
||||||
|
var updateNavigationStack: (@escaping ([AttachmentContainable]) -> [AttachmentContainable]) -> Void { get set }
|
||||||
|
var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void { get set }
|
||||||
|
|
||||||
func resetForReuse()
|
func resetForReuse()
|
||||||
func prepareForReuse()
|
func prepareForReuse()
|
||||||
@ -51,6 +53,19 @@ public protocol AttachmentMediaPickerContext {
|
|||||||
func schedule()
|
func schedule()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func generateShadowImage() -> UIImage? {
|
||||||
|
return generateImage(CGSize(width: 140.0, height: 140.0), rotatedContext: { size, context in
|
||||||
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
|
context.setShadow(offset: CGSize(), blur: 60.0, color: UIColor(white: 0.0, alpha: 0.4).cgColor)
|
||||||
|
|
||||||
|
let path = UIBezierPath(roundedRect: CGRect(x: 60.0, y: 60.0, width: 20.0, height: 20.0), cornerRadius: 11.0 - UIScreenPixel).cgPath
|
||||||
|
context.addPath(path)
|
||||||
|
context.fillPath()
|
||||||
|
})?.stretchableImage(withLeftCapWidth: 70, topCapHeight: 70)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public class AttachmentController: ViewController {
|
public class AttachmentController: ViewController {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
|
private let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
|
||||||
@ -68,11 +83,12 @@ public class AttachmentController: ViewController {
|
|||||||
private final class Node: ASDisplayNode {
|
private final class Node: ASDisplayNode {
|
||||||
private weak var controller: AttachmentController?
|
private weak var controller: AttachmentController?
|
||||||
private let dim: ASDisplayNode
|
private let dim: ASDisplayNode
|
||||||
|
private let shadowNode: ASImageNode
|
||||||
private let container: AttachmentContainer
|
private let container: AttachmentContainer
|
||||||
let panel: AttachmentPanel
|
let panel: AttachmentPanel
|
||||||
|
|
||||||
private var currentType: AttachmentButtonType?
|
private var currentType: AttachmentButtonType?
|
||||||
private var currentController: AttachmentContainable?
|
private var currentControllers: [AttachmentContainable] = []
|
||||||
|
|
||||||
private var validLayout: ContainerViewLayout?
|
private var validLayout: ContainerViewLayout?
|
||||||
private var modalProgress: CGFloat = 0.0
|
private var modalProgress: CGFloat = 0.0
|
||||||
@ -104,7 +120,9 @@ public class AttachmentController: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let wrapperNode: ASDisplayNode
|
||||||
|
|
||||||
init(controller: AttachmentController) {
|
init(controller: AttachmentController) {
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
|
|
||||||
@ -112,6 +130,11 @@ public class AttachmentController: ViewController {
|
|||||||
self.dim.alpha = 0.0
|
self.dim.alpha = 0.0
|
||||||
self.dim.backgroundColor = UIColor(white: 0.0, alpha: 0.25)
|
self.dim.backgroundColor = UIColor(white: 0.0, alpha: 0.25)
|
||||||
|
|
||||||
|
self.shadowNode = ASImageNode()
|
||||||
|
|
||||||
|
self.wrapperNode = ASDisplayNode()
|
||||||
|
self.wrapperNode.clipsToBounds = true
|
||||||
|
|
||||||
self.container = AttachmentContainer()
|
self.container = AttachmentContainer()
|
||||||
self.container.canHaveKeyboardFocus = true
|
self.container.canHaveKeyboardFocus = true
|
||||||
self.panel = AttachmentPanel(context: controller.context, updatedPresentationData: controller.updatedPresentationData)
|
self.panel = AttachmentPanel(context: controller.context, updatedPresentationData: controller.updatedPresentationData)
|
||||||
@ -119,7 +142,16 @@ public class AttachmentController: ViewController {
|
|||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.addSubnode(self.dim)
|
self.addSubnode(self.dim)
|
||||||
|
self.addSubnode(self.shadowNode)
|
||||||
|
self.addSubnode(self.wrapperNode)
|
||||||
|
|
||||||
|
self.container.controllerRemoved = { [weak self] controller in
|
||||||
|
if let strongSelf = self, let layout = strongSelf.validLayout, !strongSelf.isDismissing {
|
||||||
|
strongSelf.currentControllers = strongSelf.currentControllers.filter { $0 !== controller }
|
||||||
|
strongSelf.containerLayoutUpdated(layout, transition: .immediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.container.updateModalProgress = { [weak self] progress, transition in
|
self.container.updateModalProgress = { [weak self] progress, transition in
|
||||||
if let strongSelf = self, let layout = strongSelf.validLayout, !strongSelf.isDismissing {
|
if let strongSelf = self, let layout = strongSelf.validLayout, !strongSelf.isDismissing {
|
||||||
strongSelf.controller?.updateModalStyleOverlayTransitionFactor(progress, transition: transition)
|
strongSelf.controller?.updateModalStyleOverlayTransitionFactor(progress, transition: transition)
|
||||||
@ -218,7 +250,10 @@ public class AttachmentController: ViewController {
|
|||||||
|
|
||||||
func switchToController(_ type: AttachmentButtonType, _ ascending: Bool) {
|
func switchToController(_ type: AttachmentButtonType, _ ascending: Bool) {
|
||||||
guard self.currentType != type else {
|
guard self.currentType != type else {
|
||||||
if let controller = self.currentController {
|
if self.animating {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let controller = self.currentControllers.last {
|
||||||
controller.scrollToTopWithTabBar?()
|
controller.scrollToTopWithTabBar?()
|
||||||
controller.requestAttachmentMenuExpansion()
|
controller.requestAttachmentMenuExpansion()
|
||||||
}
|
}
|
||||||
@ -235,10 +270,22 @@ public class AttachmentController: ViewController {
|
|||||||
controller.requestAttachmentMenuExpansion = { [weak self] in
|
controller.requestAttachmentMenuExpansion = { [weak self] in
|
||||||
self?.container.update(isExpanded: true, transition: .animated(duration: 0.4, curve: .spring))
|
self?.container.update(isExpanded: true, transition: .animated(duration: 0.4, curve: .spring))
|
||||||
}
|
}
|
||||||
|
controller.updateNavigationStack = { [weak self] f in
|
||||||
let previousController = strongSelf.currentController
|
if let strongSelf = self {
|
||||||
|
strongSelf.currentControllers = f(strongSelf.currentControllers)
|
||||||
|
if let layout = strongSelf.validLayout {
|
||||||
|
strongSelf.containerLayoutUpdated(layout, transition: .animated(duration: 0.4, curve: .spring))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
controller.updateTabBarAlpha = { [weak self, weak controller] alpha, transition in
|
||||||
|
if let strongSelf = self, strongSelf.currentControllers.contains(where: { $0 === controller }) {
|
||||||
|
strongSelf.panel.updateBackgroundAlpha(alpha, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let previousController = strongSelf.currentControllers.last
|
||||||
let animateTransition = previousType != nil
|
let animateTransition = previousType != nil
|
||||||
strongSelf.currentController = controller
|
strongSelf.currentControllers = [controller]
|
||||||
|
|
||||||
if animateTransition, let snapshotView = strongSelf.container.container.view.snapshotView(afterScreenUpdates: false) {
|
if animateTransition, let snapshotView = strongSelf.container.container.view.snapshotView(afterScreenUpdates: false) {
|
||||||
snapshotView.frame = strongSelf.container.container.frame
|
snapshotView.frame = strongSelf.container.container.frame
|
||||||
@ -271,41 +318,70 @@ public class AttachmentController: ViewController {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var animating = false
|
||||||
func animateIn() {
|
func animateIn() {
|
||||||
ContainedViewLayoutTransition.animated(duration: 0.3, curve: .linear).updateAlpha(node: self.dim, alpha: 1.0)
|
guard let layout = self.validLayout else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let targetPosition = self.container.position
|
self.animating = true
|
||||||
let startPosition = targetPosition.offsetBy(dx: 0.0, dy: self.bounds.height)
|
if case .regular = layout.metrics.widthClass {
|
||||||
|
self.animating = false
|
||||||
self.container.position = startPosition
|
} else {
|
||||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring)
|
ContainedViewLayoutTransition.animated(duration: 0.3, curve: .linear).updateAlpha(node: self.dim, alpha: 1.0)
|
||||||
transition.animateView(allowUserInteraction: true, {
|
|
||||||
self.container.position = targetPosition
|
let targetPosition = self.container.position
|
||||||
})
|
let startPosition = targetPosition.offsetBy(dx: 0.0, dy: self.bounds.height)
|
||||||
|
|
||||||
|
self.container.position = startPosition
|
||||||
|
let transition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring)
|
||||||
|
transition.animateView(allowUserInteraction: true, {
|
||||||
|
self.animating = false
|
||||||
|
self.container.position = targetPosition
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func animateOut(completion: @escaping () -> Void = {}) {
|
func animateOut(completion: @escaping () -> Void = {}) {
|
||||||
self.isDismissing = true
|
self.isDismissing = true
|
||||||
|
|
||||||
let positionTransition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .easeInOut)
|
guard let layout = self.validLayout else {
|
||||||
positionTransition.updatePosition(node: self.container, position: CGPoint(x: self.container.position.x, y: self.bounds.height + self.container.bounds.height / 2.0), completion: { [weak self] _ in
|
return
|
||||||
let _ = self?.container.dismiss(transition: .immediate, completion: completion)
|
}
|
||||||
})
|
|
||||||
let alphaTransition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .easeInOut)
|
|
||||||
alphaTransition.updateAlpha(node: self.dim, alpha: 0.0)
|
|
||||||
|
|
||||||
self.controller?.updateModalStyleOverlayTransitionFactor(0.0, transition: positionTransition)
|
self.animating = true
|
||||||
|
if case .regular = layout.metrics.widthClass {
|
||||||
|
self.layer.allowsGroupOpacity = true
|
||||||
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { _ in
|
||||||
|
let _ = self.container.dismiss(transition: .immediate, completion: completion)
|
||||||
|
self.animating = false
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let positionTransition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .easeInOut)
|
||||||
|
positionTransition.updatePosition(node: self.container, position: CGPoint(x: self.container.position.x, y: self.bounds.height + self.container.bounds.height / 2.0), completion: { [weak self] _ in
|
||||||
|
let _ = self?.container.dismiss(transition: .immediate, completion: completion)
|
||||||
|
self?.animating = false
|
||||||
|
})
|
||||||
|
let alphaTransition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .easeInOut)
|
||||||
|
alphaTransition.updateAlpha(node: self.dim, alpha: 0.0)
|
||||||
|
|
||||||
|
self.controller?.updateModalStyleOverlayTransitionFactor(0.0, transition: positionTransition)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func scrollToTop() {
|
func scrollToTop() {
|
||||||
self.currentController?.scrollToTop?()
|
self.currentControllers.last?.scrollToTop?()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
if let controller = self.controller, controller.isInteractionDisabled() {
|
if let controller = self.controller, controller.isInteractionDisabled() {
|
||||||
return self.view
|
return self.view
|
||||||
} else {
|
} else {
|
||||||
return super.hitTest(point, with: event)
|
let result = super.hitTest(point, with: event)
|
||||||
|
if result == self.wrapperNode.view {
|
||||||
|
return self.dim.view
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,14 +398,48 @@ public class AttachmentController: ViewController {
|
|||||||
} else if self.modalProgress == 1.0 {
|
} else if self.modalProgress == 1.0 {
|
||||||
self.isCollapsed = true
|
self.isCollapsed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var containerLayout = layout
|
||||||
|
let containerRect: CGRect
|
||||||
|
if case .regular = layout.metrics.widthClass {
|
||||||
|
let size = CGSize(width: 390.0, height: 600.0)
|
||||||
|
let position: CGPoint
|
||||||
|
if layout.size.width > layout.size.height {
|
||||||
|
position = CGPoint(x: 225.0, y: layout.size.height - size.height - layout.intrinsicInsets.bottom - 54.0)
|
||||||
|
} else {
|
||||||
|
position = CGPoint(x: 152.0, y: layout.size.height - size.height - layout.intrinsicInsets.bottom - 54.0)
|
||||||
|
}
|
||||||
|
containerRect = CGRect(origin: position, size: size)
|
||||||
|
containerLayout.size = containerRect.size
|
||||||
|
containerLayout.intrinsicInsets.bottom = 0.0
|
||||||
|
|
||||||
|
self.wrapperNode.cornerRadius = 10.0
|
||||||
|
if #available(iOS 13.0, *) {
|
||||||
|
self.wrapperNode.layer.cornerCurve = .continuous
|
||||||
|
}
|
||||||
|
|
||||||
|
self.shadowNode.alpha = 1.0
|
||||||
|
if self.shadowNode.image == nil {
|
||||||
|
self.shadowNode.image = generateShadowImage()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
containerRect = CGRect(origin: CGPoint(), size: layout.size)
|
||||||
|
|
||||||
|
self.wrapperNode.cornerRadius = 0.0
|
||||||
|
self.shadowNode.alpha = 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let isEffecitvelyCollapsedUpdated = (self.isCollapsed || self.selectionCount > 0) != (self.panel.isCollapsed || self.panel.isSelecting)
|
let isEffecitvelyCollapsedUpdated = (self.isCollapsed || self.selectionCount > 0) != (self.panel.isCollapsed || self.panel.isSelecting)
|
||||||
let panelHeight = self.panel.update(layout: layout, buttons: self.controller?.buttons ?? [], isCollapsed: self.isCollapsed, isSelecting: self.selectionCount > 0, transition: transition)
|
let panelHeight = self.panel.update(layout: containerLayout, buttons: self.controller?.buttons ?? [], isCollapsed: self.isCollapsed, isSelecting: self.selectionCount > 0, transition: transition)
|
||||||
var panelTransition = transition
|
var panelTransition = transition
|
||||||
if isEffecitvelyCollapsedUpdated {
|
if isEffecitvelyCollapsedUpdated {
|
||||||
panelTransition = .animated(duration: 0.25, curve: .easeInOut)
|
panelTransition = .animated(duration: 0.25, curve: .easeInOut)
|
||||||
}
|
}
|
||||||
panelTransition.updateFrame(node: self.panel, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - panelHeight), size: CGSize(width: layout.size.width, height: panelHeight)))
|
panelTransition.updateFrame(node: self.panel, frame: CGRect(origin: CGPoint(x: 0.0, y: containerRect.height - panelHeight), size: CGSize(width: containerRect.width, height: panelHeight)))
|
||||||
|
|
||||||
|
transition.updateFrame(node: self.shadowNode, frame: containerRect.insetBy(dx: -60.0, dy: -60.0))
|
||||||
|
transition.updateFrame(node: self.wrapperNode, frame: containerRect)
|
||||||
|
|
||||||
if !self.isUpdatingContainer && !self.isDismissing {
|
if !self.isUpdatingContainer && !self.isDismissing {
|
||||||
self.isUpdatingContainer = true
|
self.isUpdatingContainer = true
|
||||||
@ -341,17 +451,17 @@ public class AttachmentController: ViewController {
|
|||||||
containerTransition = transition
|
containerTransition = transition
|
||||||
}
|
}
|
||||||
|
|
||||||
let controllers = self.currentController.flatMap { [$0] } ?? []
|
let controllers = self.currentControllers
|
||||||
containerTransition.updateFrame(node: self.container, frame: CGRect(origin: CGPoint(), size: layout.size))
|
containerTransition.updateFrame(node: self.container, frame: CGRect(origin: CGPoint(), size: containerRect.size))
|
||||||
|
|
||||||
var containerInsets = layout.intrinsicInsets
|
var containerInsets = containerLayout.intrinsicInsets
|
||||||
containerInsets.bottom = panelHeight
|
containerInsets.bottom = panelHeight
|
||||||
let containerLayout = layout.withUpdatedIntrinsicInsets(containerInsets)
|
let containerLayout = containerLayout.withUpdatedIntrinsicInsets(containerInsets)
|
||||||
|
|
||||||
self.container.update(layout: containerLayout, controllers: controllers, coveredByModalTransition: 0.0, transition: self.switchingController ? .immediate : transition)
|
self.container.update(layout: containerLayout, controllers: controllers, coveredByModalTransition: 0.0, transition: self.switchingController ? .immediate : transition)
|
||||||
|
|
||||||
if self.container.supernode == nil, !controllers.isEmpty && self.container.isReady {
|
if self.container.supernode == nil, !controllers.isEmpty && self.container.isReady {
|
||||||
self.addSubnode(self.container)
|
self.wrapperNode.addSubnode(self.container)
|
||||||
self.container.addSubnode(self.panel)
|
self.container.addSubnode(self.panel)
|
||||||
|
|
||||||
self.animateIn()
|
self.animateIn()
|
||||||
|
@ -410,6 +410,11 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.scrollNode.view.showsVerticalScrollIndicator = false
|
self.scrollNode.view.showsVerticalScrollIndicator = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateBackgroundAlpha(_ alpha: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
|
transition.updateAlpha(node: self.separatorNode, alpha: alpha)
|
||||||
|
transition.updateAlpha(node: self.backgroundNode, alpha: alpha)
|
||||||
|
}
|
||||||
|
|
||||||
func updateCaption(_ caption: NSAttributedString) {
|
func updateCaption(_ caption: NSAttributedString) {
|
||||||
if !caption.string.isEmpty {
|
if !caption.string.isEmpty {
|
||||||
self.loadTextNodeIfNeeded()
|
self.loadTextNodeIfNeeded()
|
||||||
|
@ -385,7 +385,7 @@ public final class CallListController: TelegramBaseController {
|
|||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue).start(next: { [weak controller, weak self] result in
|
|> deliverOnMainQueue).start(next: { [weak controller, weak self] result in
|
||||||
controller?.dismissSearch()
|
controller?.dismissSearch()
|
||||||
if let strongSelf = self, let (contactPeers, action, _, _) = result, let contactPeer = contactPeers.first, case let .peer(peer, _, _) = contactPeer {
|
if let strongSelf = self, let (contactPeers, action, _, _, _) = result, let contactPeer = contactPeers.first, case let .peer(peer, _, _) = contactPeer {
|
||||||
strongSelf.call(peer.id, isVideo: action == .videoCall, began: {
|
strongSelf.call(peer.id, isVideo: action == .videoCall, began: {
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let _ = (strongSelf.context.sharedContext.hasOngoingCall.get()
|
let _ = (strongSelf.context.sharedContext.hasOngoingCall.get()
|
||||||
|
@ -518,6 +518,8 @@ public final class ComposedPoll {
|
|||||||
|
|
||||||
private class CreatePollControllerImpl: ItemListController, AttachmentContainable {
|
private class CreatePollControllerImpl: ItemListController, AttachmentContainable {
|
||||||
public var requestAttachmentMenuExpansion: () -> Void = {}
|
public var requestAttachmentMenuExpansion: () -> Void = {}
|
||||||
|
public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> [AttachmentContainable]) -> Void = { _ in }
|
||||||
|
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
|
||||||
}
|
}
|
||||||
|
|
||||||
public func createPollController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: EnginePeer, isQuiz: Bool? = nil, completion: @escaping (ComposedPoll) -> Void) -> AttachmentContainable {
|
public func createPollController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: EnginePeer, isQuiz: Bool? = nil, completion: @escaping (ComposedPoll) -> Void) -> AttachmentContainable {
|
||||||
@ -904,8 +906,8 @@ public func createPollController(context: AccountContext, updatedPresentationDat
|
|||||||
focusItemTag = CreatePollEntryTag.solution
|
focusItemTag = CreatePollEntryTag.solution
|
||||||
ensureVisibleItemTag = focusItemTag
|
ensureVisibleItemTag = focusItemTag
|
||||||
} else {
|
} else {
|
||||||
focusItemTag = CreatePollEntryTag.text
|
// focusItemTag = CreatePollEntryTag.text
|
||||||
ensureVisibleItemTag = focusItemTag
|
// ensureVisibleItemTag = focusItemTag
|
||||||
}
|
}
|
||||||
|
|
||||||
let title: String
|
let title: String
|
||||||
@ -927,6 +929,15 @@ public func createPollController(context: AccountContext, updatedPresentationDat
|
|||||||
weak var currentTooltipController: TooltipController?
|
weak var currentTooltipController: TooltipController?
|
||||||
let controller = CreatePollControllerImpl(context: context, state: signal)
|
let controller = CreatePollControllerImpl(context: context, state: signal)
|
||||||
controller.navigationPresentation = .modal
|
controller.navigationPresentation = .modal
|
||||||
|
// controller.visibleBottomContentOffsetChanged = { [weak controller] offset in
|
||||||
|
// switch offset {
|
||||||
|
// case let .known(value):
|
||||||
|
// let backgroundAlpha: CGFloat = min(30.0, value) / 30.0
|
||||||
|
// controller?.updateTabBarAlpha(backgroundAlpha, .immediate)
|
||||||
|
// case .unknown, .none:
|
||||||
|
// controller?.updateTabBarAlpha(1.0, .immediate)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
presentControllerImpl = { [weak controller] c, a in
|
presentControllerImpl = { [weak controller] c, a in
|
||||||
controller?.present(c, in: .window(.root), with: a)
|
controller?.present(c, in: .window(.root), with: a)
|
||||||
}
|
}
|
||||||
|
@ -362,6 +362,8 @@ class CreatePollOptionItemNode: ItemListRevealOptionsItemNode, ItemListItemNode,
|
|||||||
if let checkNode = strongSelf.checkNode {
|
if let checkNode = strongSelf.checkNode {
|
||||||
transition.updateFrame(node: checkNode, frame: checkFrame)
|
transition.updateFrame(node: checkNode, frame: checkFrame)
|
||||||
checkNode.setSelected(isSelected, animated: true)
|
checkNode.setSelected(isSelected, animated: true)
|
||||||
|
|
||||||
|
transition.updateAlpha(node: checkNode, alpha: strongSelf.textNode.textView.text.isEmpty ? 0.0 : 1.0)
|
||||||
} else {
|
} else {
|
||||||
let checkNode = InteractiveCheckNode(theme: CheckNodeTheme(backgroundColor: item.presentationData.theme.list.itemSwitchColors.positiveColor, strokeColor: item.presentationData.theme.list.itemCheckColors.foregroundColor, borderColor: item.presentationData.theme.list.itemCheckColors.strokeColor, overlayBorder: false, hasInset: false, hasShadow: false))
|
let checkNode = InteractiveCheckNode(theme: CheckNodeTheme(backgroundColor: item.presentationData.theme.list.itemSwitchColors.positiveColor, strokeColor: item.presentationData.theme.list.itemCheckColors.foregroundColor, borderColor: item.presentationData.theme.list.itemCheckColors.strokeColor, overlayBorder: false, hasInset: false, hasShadow: false))
|
||||||
checkNode.setSelected(isSelected, animated: false)
|
checkNode.setSelected(isSelected, animated: false)
|
||||||
@ -372,6 +374,8 @@ class CreatePollOptionItemNode: ItemListRevealOptionsItemNode, ItemListItemNode,
|
|||||||
strongSelf.containerNode.addSubnode(checkNode)
|
strongSelf.containerNode.addSubnode(checkNode)
|
||||||
checkNode.frame = checkFrame
|
checkNode.frame = checkFrame
|
||||||
transition.animatePositionAdditive(node: checkNode, offset: CGPoint(x: -checkFrame.maxX, y: 0.0))
|
transition.animatePositionAdditive(node: checkNode, offset: CGPoint(x: -checkFrame.maxX, y: 0.0))
|
||||||
|
|
||||||
|
transition.updateAlpha(node: checkNode, alpha: strongSelf.textNode.textView.text.isEmpty ? 0.0 : 1.0)
|
||||||
}
|
}
|
||||||
} else if let checkNode = strongSelf.checkNode {
|
} else if let checkNode = strongSelf.checkNode {
|
||||||
strongSelf.checkNode = nil
|
strongSelf.checkNode = nil
|
||||||
|
@ -31,10 +31,11 @@ public struct Font {
|
|||||||
case medium
|
case medium
|
||||||
case semibold
|
case semibold
|
||||||
case bold
|
case bold
|
||||||
|
case heavy
|
||||||
|
|
||||||
var isBold: Bool {
|
var isBold: Bool {
|
||||||
switch self {
|
switch self {
|
||||||
case .medium, .semibold, .bold:
|
case .medium, .semibold, .bold, .heavy:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
@ -51,6 +52,8 @@ public struct Font {
|
|||||||
return .semibold
|
return .semibold
|
||||||
case .bold:
|
case .bold:
|
||||||
return .bold
|
return .bold
|
||||||
|
case .heavy:
|
||||||
|
return .heavy
|
||||||
default:
|
default:
|
||||||
return .regular
|
return .regular
|
||||||
}
|
}
|
||||||
@ -185,6 +188,11 @@ public struct Font {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static func heavy(_ size: CGFloat) -> UIFont {
|
||||||
|
return self.with(size: size, design: .regular, weight: .heavy, traits: [])
|
||||||
|
}
|
||||||
|
|
||||||
public static func light(_ size: CGFloat) -> UIFont {
|
public static func light(_ size: CGFloat) -> UIFont {
|
||||||
if #available(iOS 8.2, *) {
|
if #available(iOS 8.2, *) {
|
||||||
return UIFont.systemFont(ofSize: size, weight: UIFont.Weight.light)
|
return UIFont.systemFont(ofSize: size, weight: UIFont.Weight.light)
|
||||||
|
@ -109,6 +109,8 @@ public final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelega
|
|||||||
self.state.top?.value.isInFocus = isInFocus
|
self.state.top?.value.isInFocus = isInFocus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var overflowInset: CGFloat = 0.0
|
||||||
|
|
||||||
private var currentKeyboardLeftEdge: CGFloat = 0.0
|
private var currentKeyboardLeftEdge: CGFloat = 0.0
|
||||||
private var additionalKeyboardLeftEdgeOffset: CGFloat = 0.0
|
private var additionalKeyboardLeftEdgeOffset: CGFloat = 0.0
|
||||||
|
|
||||||
|
@ -61,6 +61,10 @@ public final class NavigationBarTheme {
|
|||||||
self.badgeTextColor = badgeTextColor
|
self.badgeTextColor = badgeTextColor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func withUpdatedBackgroundColor(_ color: UIColor) -> NavigationBarTheme {
|
||||||
|
return NavigationBarTheme(buttonColor: self.buttonColor, disabledButtonColor: self.disabledButtonColor, primaryTextColor: self.primaryTextColor, backgroundColor: color, enableBackgroundBlur: false, separatorColor: self.separatorColor, badgeBackgroundColor: self.badgeBackgroundColor, badgeStrokeColor: self.badgeStrokeColor, badgeTextColor: self.badgeTextColor)
|
||||||
|
}
|
||||||
|
|
||||||
public func withUpdatedSeparatorColor(_ color: UIColor) -> NavigationBarTheme {
|
public func withUpdatedSeparatorColor(_ color: UIColor) -> NavigationBarTheme {
|
||||||
return NavigationBarTheme(buttonColor: self.buttonColor, disabledButtonColor: self.disabledButtonColor, primaryTextColor: self.primaryTextColor, backgroundColor: self.backgroundColor, enableBackgroundBlur: self.enableBackgroundBlur, separatorColor: color, badgeBackgroundColor: self.badgeBackgroundColor, badgeStrokeColor: self.badgeStrokeColor, badgeTextColor: self.badgeTextColor)
|
return NavigationBarTheme(buttonColor: self.buttonColor, disabledButtonColor: self.disabledButtonColor, primaryTextColor: self.primaryTextColor, backgroundColor: self.backgroundColor, enableBackgroundBlur: self.enableBackgroundBlur, separatorColor: color, badgeBackgroundColor: self.badgeBackgroundColor, badgeStrokeColor: self.badgeStrokeColor, badgeTextColor: self.badgeTextColor)
|
||||||
}
|
}
|
||||||
@ -1334,6 +1338,8 @@ open class NavigationBar: ASDisplayNode {
|
|||||||
|
|
||||||
public var intrinsicCanTransitionInline: Bool = true
|
public var intrinsicCanTransitionInline: Bool = true
|
||||||
|
|
||||||
|
public var passthroughTouches = true
|
||||||
|
|
||||||
public var canTransitionInline: Bool {
|
public var canTransitionInline: Bool {
|
||||||
if let contentNode = self.contentNode, case .replacement = contentNode.mode {
|
if let contentNode = self.contentNode, case .replacement = contentNode.mode {
|
||||||
return false
|
return false
|
||||||
@ -1470,8 +1476,8 @@ open class NavigationBar: ASDisplayNode {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//result == self.view ||
|
|
||||||
if result == self.buttonsContainerNode.view {
|
if self.passthroughTouches && (result == self.view || result == self.buttonsContainerNode.view) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ final class NavigationTransitionCoordinator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private let container: ASDisplayNode
|
private let container: NavigationContainer
|
||||||
private let transition: NavigationTransition
|
private let transition: NavigationTransition
|
||||||
let isInteractive: Bool
|
let isInteractive: Bool
|
||||||
let topNode: ASDisplayNode
|
let topNode: ASDisplayNode
|
||||||
@ -51,7 +51,7 @@ final class NavigationTransitionCoordinator {
|
|||||||
private var currentCompletion: (() -> Void)?
|
private var currentCompletion: (() -> Void)?
|
||||||
private var didUpdateProgress: ((CGFloat, ContainedViewLayoutTransition, CGRect, CGRect) -> Void)?
|
private var didUpdateProgress: ((CGFloat, ContainedViewLayoutTransition, CGRect, CGRect) -> Void)?
|
||||||
|
|
||||||
init(transition: NavigationTransition, isInteractive: Bool, container: ASDisplayNode, topNode: ASDisplayNode, topNavigationBar: NavigationBar?, bottomNode: ASDisplayNode, bottomNavigationBar: NavigationBar?, didUpdateProgress: ((CGFloat, ContainedViewLayoutTransition, CGRect, CGRect) -> Void)? = nil) {
|
init(transition: NavigationTransition, isInteractive: Bool, container: NavigationContainer, topNode: ASDisplayNode, topNavigationBar: NavigationBar?, bottomNode: ASDisplayNode, bottomNavigationBar: NavigationBar?, didUpdateProgress: ((CGFloat, ContainedViewLayoutTransition, CGRect, CGRect) -> Void)? = nil) {
|
||||||
self.transition = transition
|
self.transition = transition
|
||||||
self.isInteractive = isInteractive
|
self.isInteractive = isInteractive
|
||||||
self.container = container
|
self.container = container
|
||||||
@ -147,7 +147,7 @@ final class NavigationTransitionCoordinator {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
canInvokeCompletion = true
|
canInvokeCompletion = true
|
||||||
transition.updateFrame(node: self.dimNode, frame: CGRect(origin: CGPoint(x: 0.0, y: dimInset), size: CGSize(width: max(0.0, topFrame.minX), height: self.container.bounds.size.height - dimInset)))
|
transition.updateFrame(node: self.dimNode, frame: CGRect(origin: CGPoint(x: 0.0, y: dimInset), size: CGSize(width: max(0.0, topFrame.minX + self.container.overflowInset), height: self.container.bounds.size.height - dimInset)))
|
||||||
transition.updateFrame(node: self.shadowNode, frame: CGRect(origin: CGPoint(x: self.dimNode.frame.maxX - shadowWidth, y: dimInset), size: CGSize(width: shadowWidth, height: containerSize.height - dimInset)))
|
transition.updateFrame(node: self.shadowNode, frame: CGRect(origin: CGPoint(x: self.dimNode.frame.maxX - shadowWidth, y: dimInset), size: CGSize(width: shadowWidth, height: containerSize.height - dimInset)))
|
||||||
transition.updateAlpha(node: self.dimNode, alpha: (1.0 - position) * 0.15)
|
transition.updateAlpha(node: self.dimNode, alpha: (1.0 - position) * 0.15)
|
||||||
transition.updateAlpha(node: self.shadowNode, alpha: (1.0 - position) * 0.9)
|
transition.updateAlpha(node: self.shadowNode, alpha: (1.0 - position) * 0.9)
|
||||||
|
@ -174,6 +174,13 @@ open class ItemListController: ViewController, KeyShortcutResponder, Presentable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var visibleBottomContentOffset: ListViewVisibleContentOffset {
|
||||||
|
if self.isNodeLoaded {
|
||||||
|
return (self.displayNode as! ItemListControllerNode).listNode.visibleBottomContentOffset()
|
||||||
|
} else {
|
||||||
|
return .unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
public var visibleBottomContentOffsetChanged: ((ListViewVisibleContentOffset) -> Void)? {
|
public var visibleBottomContentOffsetChanged: ((ListViewVisibleContentOffset) -> Void)? {
|
||||||
didSet {
|
didSet {
|
||||||
if self.isNodeLoaded {
|
if self.isNodeLoaded {
|
||||||
|
@ -166,10 +166,10 @@ public class ItemListVenueItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
|
|
||||||
self.isAccessibilityElement = true
|
self.isAccessibilityElement = true
|
||||||
|
|
||||||
self.addSubnode(self.iconNode)
|
|
||||||
self.addSubnode(self.titleNode)
|
self.addSubnode(self.titleNode)
|
||||||
self.addSubnode(self.addressNode)
|
self.addSubnode(self.addressNode)
|
||||||
self.addSubnode(self.infoButton)
|
self.addSubnode(self.infoButton)
|
||||||
|
self.addSubnode(self.iconNode)
|
||||||
|
|
||||||
self.infoButton.addTarget(self, action: #selector(self.infoPressed), forControlEvents: .touchUpInside)
|
self.infoButton.addTarget(self, action: #selector(self.infoPressed), forControlEvents: .touchUpInside)
|
||||||
}
|
}
|
||||||
@ -301,7 +301,7 @@ public class ItemListVenueItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
strongSelf.topStripeNode.removeFromSupernode()
|
strongSelf.topStripeNode.removeFromSupernode()
|
||||||
}
|
}
|
||||||
if strongSelf.bottomStripeNode.supernode == nil {
|
if strongSelf.bottomStripeNode.supernode == nil {
|
||||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 1)
|
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0)
|
||||||
}
|
}
|
||||||
if strongSelf.maskNode.supernode != nil {
|
if strongSelf.maskNode.supernode != nil {
|
||||||
strongSelf.maskNode.removeFromSupernode()
|
strongSelf.maskNode.removeFromSupernode()
|
||||||
@ -377,6 +377,7 @@ public class ItemListVenueItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
shimmerNode = ShimmerEffectNode()
|
shimmerNode = ShimmerEffectNode()
|
||||||
strongSelf.placeholderNode = shimmerNode
|
strongSelf.placeholderNode = shimmerNode
|
||||||
if strongSelf.bottomStripeNode.supernode != nil {
|
if strongSelf.bottomStripeNode.supernode != nil {
|
||||||
|
|
||||||
strongSelf.insertSubnode(shimmerNode, belowSubnode: strongSelf.bottomStripeNode)
|
strongSelf.insertSubnode(shimmerNode, belowSubnode: strongSelf.bottomStripeNode)
|
||||||
} else {
|
} else {
|
||||||
strongSelf.addSubnode(shimmerNode)
|
strongSelf.addSubnode(shimmerNode)
|
||||||
@ -403,6 +404,8 @@ public class ItemListVenueItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
shapes.append(.roundedRectLine(startPoint: CGPoint(x: subtitleFrame.minX, y: subtitleFrame.minY + floor((subtitleFrame.height - lineDiameter) / 2.0)), width: subtitleLineWidth, diameter: lineDiameter))
|
shapes.append(.roundedRectLine(startPoint: CGPoint(x: subtitleFrame.minX, y: subtitleFrame.minY + floor((subtitleFrame.height - lineDiameter) / 2.0)), width: subtitleLineWidth, diameter: lineDiameter))
|
||||||
|
|
||||||
shimmerNode.update(backgroundColor: placeholderBackgroundColor, foregroundColor: item.presentationData.theme.list.mediaPlaceholderColor, shimmeringColor: item.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: shapes, size: layout.contentSize)
|
shimmerNode.update(backgroundColor: placeholderBackgroundColor, foregroundColor: item.presentationData.theme.list.mediaPlaceholderColor, shimmeringColor: item.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: shapes, size: layout.contentSize)
|
||||||
|
|
||||||
|
strongSelf.iconNode.removeFromSupernode()
|
||||||
} else if let shimmerNode = strongSelf.placeholderNode {
|
} else if let shimmerNode = strongSelf.placeholderNode {
|
||||||
strongSelf.placeholderNode = nil
|
strongSelf.placeholderNode = nil
|
||||||
shimmerNode.removeFromSupernode()
|
shimmerNode.removeFromSupernode()
|
||||||
@ -418,16 +421,10 @@ public class ItemListVenueItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
if highlighted {
|
if highlighted {
|
||||||
self.highlightedBackgroundNode.alpha = 1.0
|
self.highlightedBackgroundNode.alpha = 1.0
|
||||||
if self.highlightedBackgroundNode.supernode == nil {
|
if self.highlightedBackgroundNode.supernode == nil {
|
||||||
var anchorNode: ASDisplayNode?
|
|
||||||
if self.bottomStripeNode.supernode != nil {
|
if self.bottomStripeNode.supernode != nil {
|
||||||
anchorNode = self.bottomStripeNode
|
self.insertSubnode(self.highlightedBackgroundNode, aboveSubnode: self.bottomStripeNode)
|
||||||
} else if self.topStripeNode.supernode != nil {
|
|
||||||
anchorNode = self.topStripeNode
|
|
||||||
} else if self.backgroundNode.supernode != nil {
|
} else if self.backgroundNode.supernode != nil {
|
||||||
anchorNode = self.backgroundNode
|
self.insertSubnode(self.highlightedBackgroundNode, aboveSubnode: self.backgroundNode)
|
||||||
}
|
|
||||||
if let anchorNode = anchorNode {
|
|
||||||
self.insertSubnode(self.highlightedBackgroundNode, aboveSubnode: anchorNode)
|
|
||||||
} else {
|
} else {
|
||||||
self.addSubnode(self.highlightedBackgroundNode)
|
self.addSubnode(self.highlightedBackgroundNode)
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,8 @@ typedef enum {
|
|||||||
|
|
||||||
@property (nonatomic, copy) void(^recognizedQRCode)(NSString *code);
|
@property (nonatomic, copy) void(^recognizedQRCode)(NSString *code);
|
||||||
|
|
||||||
|
@property (nonatomic, copy) void(^finishedTransitionIn)(void);
|
||||||
|
|
||||||
@property (nonatomic, copy) CGRect(^beginTransitionOut)(void);
|
@property (nonatomic, copy) CGRect(^beginTransitionOut)(void);
|
||||||
@property (nonatomic, copy) void(^finishedTransitionOut)(void);
|
@property (nonatomic, copy) void(^finishedTransitionOut)(void);
|
||||||
@property (nonatomic, copy) void(^customPresentOverlayController)(TGOverlayController *(^)(id<LegacyComponentsContext>));
|
@property (nonatomic, copy) void(^customPresentOverlayController)(TGOverlayController *(^)(id<LegacyComponentsContext>));
|
||||||
|
@ -26,6 +26,8 @@
|
|||||||
|
|
||||||
TGCameraPreviewView *_previewView;
|
TGCameraPreviewView *_previewView;
|
||||||
__weak PGCamera *_camera;
|
__weak PGCamera *_camera;
|
||||||
|
|
||||||
|
UIInterfaceOrientation _innerInterfaceOrientation;
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ -233,10 +235,22 @@
|
|||||||
{
|
{
|
||||||
void(^block)(void) = ^
|
void(^block)(void) = ^
|
||||||
{
|
{
|
||||||
_wrapperView.transform = CGAffineTransformMakeRotation(-1 * TGRotationForInterfaceOrientation(orientation));
|
CGAffineTransform transform = CGAffineTransformMakeRotation(-1 * TGRotationForInterfaceOrientation(orientation));
|
||||||
_wrapperView.frame = self.bounds;
|
CGFloat scale = 1.0;
|
||||||
|
if (self.frame.size.width != 0.0) {
|
||||||
|
scale = self.frame.size.height / self.frame.size.width;
|
||||||
|
}
|
||||||
|
if (_innerInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
|
||||||
|
transform = CGAffineTransformScale(transform, scale, scale);
|
||||||
|
} else if (_innerInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
|
||||||
|
transform = CGAffineTransformScale(transform, scale, scale);
|
||||||
|
}
|
||||||
|
_wrapperView.transform = transform;
|
||||||
|
[self layoutSubviews];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_innerInterfaceOrientation = orientation;
|
||||||
|
|
||||||
if (animated)
|
if (animated)
|
||||||
[UIView animateWithDuration:0.3f animations:block];
|
[UIView animateWithDuration:0.3f animations:block];
|
||||||
else
|
else
|
||||||
@ -247,12 +261,19 @@
|
|||||||
{
|
{
|
||||||
[super layoutSubviews];
|
[super layoutSubviews];
|
||||||
|
|
||||||
_wrapperView.frame = self.bounds;
|
_wrapperView.bounds = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
|
||||||
|
_wrapperView.center = CGPointMake(self.bounds.size.width / 2.0, self.bounds.size.height / 2.0);
|
||||||
|
|
||||||
TGCameraPreviewView *previewView = _previewView;
|
TGCameraPreviewView *previewView = _previewView;
|
||||||
if (previewView.superview == _wrapperView)
|
if (previewView.superview == _wrapperView)
|
||||||
previewView.frame = self.bounds;
|
previewView.frame = self.bounds;
|
||||||
|
|
||||||
|
// if (_innerInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
|
||||||
|
// _wrapperView.frame = CGRectOffset(_wrapperView.frame, 0, 100.0);
|
||||||
|
// } else if (_innerInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
|
||||||
|
// _wrapperView.frame = CGRectOffset(_wrapperView.frame, 0, -100.0);
|
||||||
|
// }
|
||||||
|
|
||||||
_iconView.frame = CGRectMake(self.frame.size.width - _iconView.frame.size.width - 3.0, 3.0 - TGScreenPixel, _iconView.frame.size.width, _iconView.frame.size.height);
|
_iconView.frame = CGRectMake(self.frame.size.width - _iconView.frame.size.width - 3.0, 3.0 - TGScreenPixel, _iconView.frame.size.width, _iconView.frame.size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2225,11 +2225,21 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
|||||||
|
|
||||||
if (!CGRectEqualToRect(fromFrame, CGRectZero))
|
if (!CGRectEqualToRect(fromFrame, CGRectZero))
|
||||||
{
|
{
|
||||||
|
__weak TGCameraController *weakSelf = self;
|
||||||
POPSpringAnimation *frameAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewFrame];
|
POPSpringAnimation *frameAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewFrame];
|
||||||
frameAnimation.fromValue = [NSValue valueWithCGRect:fromFrame];
|
frameAnimation.fromValue = [NSValue valueWithCGRect:fromFrame];
|
||||||
frameAnimation.toValue = [NSValue valueWithCGRect:toFrame];
|
frameAnimation.toValue = [NSValue valueWithCGRect:toFrame];
|
||||||
frameAnimation.springSpeed = 20;
|
frameAnimation.springSpeed = 20;
|
||||||
frameAnimation.springBounciness = 1;
|
frameAnimation.springBounciness = 1;
|
||||||
|
frameAnimation.completionBlock = ^(POPAnimation *anim, BOOL finished) {
|
||||||
|
__strong TGCameraController *strongSelf = weakSelf;
|
||||||
|
if (strongSelf == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (strongSelf.finishedTransitionIn != NULL) {
|
||||||
|
;strongSelf.finishedTransitionIn();
|
||||||
|
}
|
||||||
|
};
|
||||||
[_previewView pop_addAnimation:frameAnimation forKey:@"frame"];
|
[_previewView pop_addAnimation:frameAnimation forKey:@"frame"];
|
||||||
|
|
||||||
POPSpringAnimation *cornersFrameAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewFrame];
|
POPSpringAnimation *cornersFrameAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewFrame];
|
||||||
|
@ -927,6 +927,11 @@
|
|||||||
grouping = false;
|
grouping = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (TGPhotoPaintEntity *entity in adjustments.paintingData.entities) {
|
||||||
|
if (entity.animated) {
|
||||||
|
grouping = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -942,8 +947,12 @@
|
|||||||
|
|
||||||
NSAttributedString *caption = [editingContext captionForItem:asset];
|
NSAttributedString *caption = [editingContext captionForItem:asset];
|
||||||
|
|
||||||
if (editingContext.isForcedCaption && num > 0) {
|
if (editingContext.isForcedCaption) {
|
||||||
caption = nil;
|
if (grouping && num > 0) {
|
||||||
|
caption = nil;
|
||||||
|
} else if (!grouping && num < selectedItems.count - 1) {
|
||||||
|
caption = nil;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (asset.type)
|
switch (asset.type)
|
||||||
|
@ -406,6 +406,8 @@ open class LegacyController: ViewController, PresentableController, AttachmentCo
|
|||||||
public var disposables = DisposableSet()
|
public var disposables = DisposableSet()
|
||||||
|
|
||||||
open var requestAttachmentMenuExpansion: () -> Void = {}
|
open var requestAttachmentMenuExpansion: () -> Void = {}
|
||||||
|
open var updateNavigationStack: (@escaping ([AttachmentContainable]) -> [AttachmentContainable]) -> Void = { _ in }
|
||||||
|
open var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
|
||||||
|
|
||||||
public init(presentation: LegacyControllerPresentation, theme: PresentationTheme? = nil, strings: PresentationStrings? = nil, initialLayout: ContainerViewLayout? = nil) {
|
public init(presentation: LegacyControllerPresentation, theme: PresentationTheme? = nil, strings: PresentationStrings? = nil, initialLayout: ContainerViewLayout? = nil) {
|
||||||
self.sizeClass.set(SSignal.single(UIUserInterfaceSizeClass.compact.rawValue as NSNumber))
|
self.sizeClass.set(SSignal.single(UIUserInterfaceSizeClass.compact.rawValue as NSNumber))
|
||||||
|
@ -61,6 +61,10 @@ private func generateExtensionImage(colors: (UInt32, UInt32)) -> UIImage? {
|
|||||||
|
|
||||||
context.restoreGState()
|
context.restoreGState()
|
||||||
|
|
||||||
|
context.beginPath()
|
||||||
|
let _ = try? drawSvgPath(context, path: "M6,0 L26.7573593,0 C27.5530088,-8.52837125e-16 28.3160705,0.316070521 28.8786797,0.878679656 L39.1213203,11.1213203 C39.6839295,11.6839295 40,12.4469912 40,13.2426407 L40,34 C40,37.3137085 37.3137085,40 34,40 L6,40 C2.6862915,40 4.05812251e-16,37.3137085 0,34 L0,6 C-4.05812251e-16,2.6862915 2.6862915,6.08718376e-16 6,0 ")
|
||||||
|
context.clip()
|
||||||
|
|
||||||
context.setFillColor(UIColor(rgb: 0xffffff, alpha: 0.2).cgColor)
|
context.setFillColor(UIColor(rgb: 0xffffff, alpha: 0.2).cgColor)
|
||||||
context.translateBy(x: 40.0 - 14.0, y: 0.0)
|
context.translateBy(x: 40.0 - 14.0, y: 0.0)
|
||||||
let _ = try? drawSvgPath(context, path: "M-1,0 L14,0 L14,15 L14,14 C14,12.8954305 13.1045695,12 12,12 L4,12 C2.8954305,12 2,11.1045695 2,10 L2,2 C2,0.8954305 1.1045695,-2.02906125e-16 0,0 L-1,0 L-1,0 Z ")
|
let _ = try? drawSvgPath(context, path: "M-1,0 L14,0 L14,15 L14,14 C14,12.8954305 13.1045695,12 12,12 L4,12 C2.8954305,12 2,11.1045695 2,10 L2,2 C2,0.8954305 1.1045695,-2.02906125e-16 0,0 L-1,0 L-1,0 Z ")
|
||||||
@ -894,10 +898,10 @@ public final class ListMessageFileItemNode: ListMessageNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
transition.updateFrame(node: strongSelf.separatorNode, frame: CGRect(origin: CGPoint(x: leftInset + leftOffset, y: nodeLayout.contentSize.height - UIScreenPixel), size: CGSize(width: params.width - leftInset - leftOffset, height: UIScreenPixel)))
|
transition.updateFrame(node: strongSelf.separatorNode, frame: CGRect(origin: CGPoint(x: leftInset + leftOffset, y: nodeLayout.contentSize.height - UIScreenPixel), size: CGSize(width: params.width - leftInset - leftOffset, height: UIScreenPixel)))
|
||||||
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: nodeLayout.contentSize.height + UIScreenPixel))
|
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: nodeLayout.size.height + UIScreenPixel))
|
||||||
|
|
||||||
if let backgroundNode = strongSelf.backgroundNode {
|
if let backgroundNode = strongSelf.backgroundNode {
|
||||||
backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -nodeLayout.insets.top), size: CGSize(width: params.width, height: nodeLayout.contentSize.height))
|
backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -nodeLayout.insets.top), size: CGSize(width: params.width, height: nodeLayout.size.height - nodeLayout.insets.bottom))
|
||||||
}
|
}
|
||||||
|
|
||||||
switch item.style {
|
switch item.style {
|
||||||
|
@ -72,7 +72,9 @@ public final class LocationPickerController: ViewController, AttachmentContainab
|
|||||||
private var interaction: LocationPickerInteraction?
|
private var interaction: LocationPickerInteraction?
|
||||||
|
|
||||||
public var requestAttachmentMenuExpansion: () -> Void = {}
|
public var requestAttachmentMenuExpansion: () -> Void = {}
|
||||||
|
public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> [AttachmentContainable]) -> Void = { _ in }
|
||||||
|
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
|
||||||
|
|
||||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, mode: LocationPickerMode, completion: @escaping (TelegramMediaMap, String?) -> Void) {
|
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, mode: LocationPickerMode, completion: @escaping (TelegramMediaMap, String?) -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
@ -319,6 +321,8 @@ public final class LocationPickerController: ViewController, AttachmentContainab
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
self.navigationBar?.passthroughTouches = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
@ -342,4 +346,8 @@ public final class LocationPickerController: ViewController, AttachmentContainab
|
|||||||
self.interaction?.dismissSearch()
|
self.interaction?.dismissSearch()
|
||||||
self.scrollToTop?()
|
self.scrollToTop?()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func prepareForReuse() {
|
||||||
|
self.updateTabBarAlpha(1.0, .animated(duration: 0.25, curve: .easeInOut))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ enum LegacyMediaPickerGallerySource {
|
|||||||
case selection(item: TGMediaSelectableItem)
|
case selection(item: TGMediaSelectableItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
func presentLegacyMediaPickerGallery(context: AccountContext, peer: EnginePeer?, chatLocation: ChatLocation?, presentationData: PresentationData, source: LegacyMediaPickerGallerySource, immediateThumbnail: UIImage?, selectionContext: TGMediaSelectionContext?, editingContext: TGMediaEditingContext, hasSilentPosting: Bool, hasSchedule: Bool, hasTimer: Bool, updateHiddenMedia: @escaping (String?) -> Void, initialLayout: ContainerViewLayout?, transitionHostView: @escaping () -> UIView?, transitionView: @escaping (String) -> UIView?, completed: @escaping (TGMediaSelectableItem & TGMediaEditableItem, Bool, Int32?) -> Void, presentStickers: ((@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?)?, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, present: @escaping (ViewController, Any?) -> Void) {
|
func presentLegacyMediaPickerGallery(context: AccountContext, peer: EnginePeer?, chatLocation: ChatLocation?, presentationData: PresentationData, source: LegacyMediaPickerGallerySource, immediateThumbnail: UIImage?, selectionContext: TGMediaSelectionContext?, editingContext: TGMediaEditingContext, hasSilentPosting: Bool, hasSchedule: Bool, hasTimer: Bool, updateHiddenMedia: @escaping (String?) -> Void, initialLayout: ContainerViewLayout?, transitionHostView: @escaping () -> UIView?, transitionView: @escaping (String) -> UIView?, completed: @escaping (TGMediaSelectableItem & TGMediaEditableItem, Bool, Int32?) -> Void, presentStickers: ((@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?)?, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, present: @escaping (ViewController, Any?) -> Void, finishedTransitionIn: @escaping () -> Void) {
|
||||||
let reminder = peer?.id == context.account.peerId
|
let reminder = peer?.id == context.account.peerId
|
||||||
|
|
||||||
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme, initialLayout: nil)
|
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme, initialLayout: nil)
|
||||||
@ -179,6 +179,8 @@ func presentLegacyMediaPickerGallery(context: AccountContext, peer: EnginePeer?,
|
|||||||
}
|
}
|
||||||
controller.finishedTransitionIn = { [weak model] _, _ in
|
controller.finishedTransitionIn = { [weak model] _, _ in
|
||||||
model?.interfaceView.setSelectedItemsModel(model?.selectedItemsModel)
|
model?.interfaceView.setSelectedItemsModel(model?.selectedItemsModel)
|
||||||
|
|
||||||
|
finishedTransitionIn()
|
||||||
}
|
}
|
||||||
controller.completedTransitionOut = { [weak legacyController] in
|
controller.completedTransitionOut = { [weak legacyController] in
|
||||||
updateHiddenMedia(nil)
|
updateHiddenMedia(nil)
|
||||||
|
@ -29,7 +29,8 @@ class MediaAssetsContext: NSObject, PHPhotoLibraryChangeObserver {
|
|||||||
self.changeSink.putNext(changeInstance)
|
self.changeSink.putNext(changeInstance)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchResultAssets(_ initialFetchResult: PHFetchResult<PHAsset>) -> Signal<PHFetchResult<PHAsset>?, NoError> {
|
func fetchAssets(_ collection: PHAssetCollection) -> Signal<PHFetchResult<PHAsset>, NoError> {
|
||||||
|
let initialFetchResult = PHAsset.fetchAssets(in: collection, options: nil)
|
||||||
let fetchResult = Atomic<PHFetchResult<PHAsset>>(value: initialFetchResult)
|
let fetchResult = Atomic<PHFetchResult<PHAsset>>(value: initialFetchResult)
|
||||||
return .single(initialFetchResult)
|
return .single(initialFetchResult)
|
||||||
|> then(
|
|> then(
|
||||||
@ -45,16 +46,33 @@ class MediaAssetsContext: NSObject, PHPhotoLibraryChangeObserver {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fetchAssetsCollections(_ type: PHAssetCollectionType) -> Signal<PHFetchResult<PHAssetCollection>, NoError> {
|
||||||
|
let initialFetchResult = PHAssetCollection.fetchAssetCollections(with: type, subtype: .any, options: nil)
|
||||||
|
let fetchResult = Atomic<PHFetchResult<PHAssetCollection>>(value: initialFetchResult)
|
||||||
|
return .single(initialFetchResult)
|
||||||
|
|> then(
|
||||||
|
self.changeSink.signal()
|
||||||
|
|> mapToSignal { change in
|
||||||
|
if let updatedFetchResult = change.changeDetails(for: fetchResult.with { $0 })?.fetchResultAfterChanges {
|
||||||
|
let _ = fetchResult.modify { _ in return updatedFetchResult }
|
||||||
|
return .single(updatedFetchResult)
|
||||||
|
} else {
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func recentAssets() -> Signal<PHFetchResult<PHAsset>?, NoError> {
|
func recentAssets() -> Signal<PHFetchResult<PHAsset>?, NoError> {
|
||||||
let collections = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .smartAlbumUserLibrary, options: nil)
|
let collections = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .smartAlbumUserLibrary, options: nil)
|
||||||
if let collection = collections.firstObject {
|
if let collection = collections.firstObject {
|
||||||
let initialFetchResult = PHAsset.fetchAssets(in: collection, options: nil)
|
return fetchAssets(collection)
|
||||||
return fetchResultAssets(initialFetchResult)
|
|> map(Optional.init)
|
||||||
} else {
|
} else {
|
||||||
return .single(nil)
|
return .single(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mediaAccess() -> Signal<PHAuthorizationStatus, NoError> {
|
func mediaAccess() -> Signal<PHAuthorizationStatus, NoError> {
|
||||||
let initialStatus: PHAuthorizationStatus
|
let initialStatus: PHAuthorizationStatus
|
||||||
if #available(iOS 14.0, *) {
|
if #available(iOS 14.0, *) {
|
||||||
|
367
submodules/MediaPickerUI/Sources/MediaGroupsAlbumGridItem.swift
Normal file
367
submodules/MediaPickerUI/Sources/MediaGroupsAlbumGridItem.swift
Normal file
@ -0,0 +1,367 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import Display
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import SwiftSignalKit
|
||||||
|
import TelegramPresentationData
|
||||||
|
import ItemListUI
|
||||||
|
import MergeLists
|
||||||
|
import Photos
|
||||||
|
|
||||||
|
private struct MediaGroupsGridAlbumEntry: Comparable, Identifiable {
|
||||||
|
let theme: PresentationTheme
|
||||||
|
let index: Int
|
||||||
|
let collection: PHAssetCollection
|
||||||
|
let firstItem: PHAsset?
|
||||||
|
let count: String
|
||||||
|
|
||||||
|
var stableId: String {
|
||||||
|
return self.collection.localIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
static func ==(lhs: MediaGroupsGridAlbumEntry, rhs: MediaGroupsGridAlbumEntry) -> Bool {
|
||||||
|
if lhs.theme !== rhs.theme {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.index != rhs.index {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.collection != rhs.collection {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.firstItem != rhs.firstItem {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.count != rhs.count {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
static func <(lhs: MediaGroupsGridAlbumEntry, rhs: MediaGroupsGridAlbumEntry) -> Bool {
|
||||||
|
return lhs.index < rhs.index
|
||||||
|
}
|
||||||
|
|
||||||
|
func item(action: @escaping (PHAssetCollection) -> Void) -> ListViewItem {
|
||||||
|
return MediaGroupsGridAlbumItem(theme: theme, collection: self.collection, firstItem: self.firstItem, count: self.count, action: action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class MediaGroupsGridAlbumItem: ListViewItem {
|
||||||
|
let theme: PresentationTheme
|
||||||
|
let collection: PHAssetCollection
|
||||||
|
let firstItem: PHAsset?
|
||||||
|
let count: String
|
||||||
|
let action: (PHAssetCollection) -> Void
|
||||||
|
|
||||||
|
public init(theme: PresentationTheme, collection: PHAssetCollection, firstItem: PHAsset?, count: String, action: @escaping (PHAssetCollection) -> Void) {
|
||||||
|
self.theme = theme
|
||||||
|
self.collection = collection
|
||||||
|
self.firstItem = firstItem
|
||||||
|
self.count = count
|
||||||
|
self.action = action
|
||||||
|
}
|
||||||
|
|
||||||
|
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||||
|
async {
|
||||||
|
let node = MediaGroupsGridAlbumItemNode()
|
||||||
|
let (nodeLayout, apply) = node.asyncLayout()(self, params)
|
||||||
|
node.insets = nodeLayout.insets
|
||||||
|
node.contentSize = nodeLayout.contentSize
|
||||||
|
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
completion(node, {
|
||||||
|
return (nil, { _ in
|
||||||
|
apply(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
assert(node() is MediaGroupsGridAlbumItemNode)
|
||||||
|
if let nodeValue = node() as? MediaGroupsGridAlbumItemNode {
|
||||||
|
let layout = nodeValue.asyncLayout()
|
||||||
|
async {
|
||||||
|
let (nodeLayout, apply) = layout(self, params)
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
completion(nodeLayout, { _ in
|
||||||
|
apply(animation.isAnimated)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var selectable = true
|
||||||
|
public func selected(listView: ListView) {
|
||||||
|
self.action(self.collection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private let textFont = Font.regular(15.0)
|
||||||
|
|
||||||
|
private final class MediaGroupsGridAlbumItemNode : ListViewItemNode {
|
||||||
|
private let containerNode: ASDisplayNode
|
||||||
|
private let imageNode: ImageNode
|
||||||
|
private let titleNode: TextNode
|
||||||
|
private let countNode: TextNode
|
||||||
|
|
||||||
|
var item: MediaGroupsGridAlbumItem?
|
||||||
|
|
||||||
|
init() {
|
||||||
|
self.containerNode = ASDisplayNode()
|
||||||
|
|
||||||
|
self.imageNode = ImageNode()
|
||||||
|
self.imageNode.clipsToBounds = true
|
||||||
|
self.imageNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 62.0, height: 62.0))
|
||||||
|
|
||||||
|
self.titleNode = TextNode()
|
||||||
|
self.titleNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
|
self.countNode = TextNode()
|
||||||
|
self.countNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
|
super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false)
|
||||||
|
|
||||||
|
self.addSubnode(self.containerNode)
|
||||||
|
self.containerNode.addSubnode(self.imageNode)
|
||||||
|
self.containerNode.addSubnode(self.titleNode)
|
||||||
|
self.containerNode.addSubnode(self.countNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func didLoad() {
|
||||||
|
super.didLoad()
|
||||||
|
|
||||||
|
self.imageNode.cornerRadius = 10.0
|
||||||
|
if #available(iOS 13.0, *) {
|
||||||
|
self.imageNode.layer.cornerCurve = .continuous
|
||||||
|
}
|
||||||
|
|
||||||
|
self.containerNode.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func asyncLayout() -> (MediaGroupsGridAlbumItem, ListViewItemLayoutParams) -> (ListViewItemNodeLayout, (Bool) -> Void) {
|
||||||
|
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||||
|
let makeCountLayout = TextNode.asyncLayout(self.countNode)
|
||||||
|
|
||||||
|
return { [weak self] item, params in
|
||||||
|
let title = NSAttributedString(string: item.collection.localizedTitle ?? "", font: textFont, textColor: item.theme.list.itemPrimaryTextColor)
|
||||||
|
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: title, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 170.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
|
let count = NSAttributedString(string: item.count, font: textFont, textColor: item.theme.list.itemSecondaryTextColor)
|
||||||
|
let (countLayout, countApply) = makeCountLayout(TextNodeLayoutArguments(attributedString: count, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 170.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
|
let itemLayout = ListViewItemNodeLayout(contentSize: CGSize(width: 220.0, height: 182.0), insets: UIEdgeInsets())
|
||||||
|
return (itemLayout, { animated in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.item = item
|
||||||
|
|
||||||
|
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 220.0, height: 220.0))
|
||||||
|
|
||||||
|
if let firstItem = item.firstItem {
|
||||||
|
let scale = min(2.0, UIScreenScale)
|
||||||
|
let targetSize = CGSize(width: 160.0 * scale, height: 160.0 * scale)
|
||||||
|
strongSelf.imageNode.setSignal(assetImage(asset: firstItem, targetSize: targetSize, exact: false))
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.imageNode.frame = CGRect(origin: CGPoint(x: 6.0, y: 0.0), size: CGSize(width: 170.0, height: 170.0))
|
||||||
|
|
||||||
|
let _ = titleApply()
|
||||||
|
strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: 6.0, y: 176.0), size: titleLayout.size)
|
||||||
|
|
||||||
|
let _ = countApply()
|
||||||
|
strongSelf.countNode.frame = CGRect(origin: CGPoint(x: 6.0, y: 196.0), size: countLayout.size)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||||
|
super.animateInsertion(currentTimestamp, duration: duration, short: short)
|
||||||
|
|
||||||
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||||
|
super.animateRemoved(currentTimestamp, duration: duration)
|
||||||
|
|
||||||
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func animateAdded(_ currentTimestamp: Double, duration: Double) {
|
||||||
|
super.animateAdded(currentTimestamp, duration: duration)
|
||||||
|
|
||||||
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct MediaGroupsAlbumGridItemNodeTransition {
|
||||||
|
let deletions: [ListViewDeleteItem]
|
||||||
|
let insertions: [ListViewInsertItem]
|
||||||
|
let updates: [ListViewUpdateItem]
|
||||||
|
let entries: [MediaGroupsGridAlbumEntry]
|
||||||
|
}
|
||||||
|
|
||||||
|
private func preparedTransition(action: @escaping (PHAssetCollection) -> Void, from fromEntries: [MediaGroupsGridAlbumEntry], to toEntries: [MediaGroupsGridAlbumEntry]) -> MediaGroupsAlbumGridItemNodeTransition {
|
||||||
|
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||||
|
|
||||||
|
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||||
|
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(action: action), directionHint: .Down) }
|
||||||
|
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(action: action), directionHint: nil) }
|
||||||
|
|
||||||
|
return MediaGroupsAlbumGridItemNodeTransition(deletions: deletions, insertions: insertions, updates: updates, entries: toEntries)
|
||||||
|
}
|
||||||
|
|
||||||
|
final class MediaGroupsAlbumGridItem: ListViewItem {
|
||||||
|
let presentationData: ItemListPresentationData
|
||||||
|
let collections: [PHAssetCollection]
|
||||||
|
let action: (PHAssetCollection) -> Void
|
||||||
|
|
||||||
|
public init(presentationData: ItemListPresentationData, collections: [PHAssetCollection], action: @escaping (PHAssetCollection) -> Void) {
|
||||||
|
self.presentationData = presentationData
|
||||||
|
self.collections = collections
|
||||||
|
self.action = action
|
||||||
|
}
|
||||||
|
|
||||||
|
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
let node = MediaGroupsAlbumGridItemNode()
|
||||||
|
let makeLayout = node.asyncLayout()
|
||||||
|
async {
|
||||||
|
let (nodeLayout, nodeApply) = makeLayout(self, params)
|
||||||
|
node.contentSize = nodeLayout.contentSize
|
||||||
|
node.insets = nodeLayout.insets
|
||||||
|
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
completion(node, nodeApply)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
if let nodeValue = node() as? MediaGroupsAlbumGridItemNode {
|
||||||
|
let layout = nodeValue.asyncLayout()
|
||||||
|
async {
|
||||||
|
let (nodeLayout, apply) = layout(self, params)
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
completion(nodeLayout, { info in
|
||||||
|
apply().1(info)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var selectable: Bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private let titleFont = Font.bold(20.0)
|
||||||
|
|
||||||
|
private class MediaGroupsAlbumGridItemNode: ListViewItemNode {
|
||||||
|
private var item: MediaGroupsAlbumGridItem?
|
||||||
|
private var layoutParams: ListViewItemLayoutParams?
|
||||||
|
|
||||||
|
private let listNode: ListView
|
||||||
|
private var entries: [MediaGroupsGridAlbumEntry]?
|
||||||
|
private var enqueuedTransitions: [MediaGroupsAlbumGridItemNodeTransition] = []
|
||||||
|
|
||||||
|
init() {
|
||||||
|
self.listNode = ListView()
|
||||||
|
self.listNode.transform = CATransform3DMakeRotation(-CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
|
||||||
|
|
||||||
|
super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false)
|
||||||
|
|
||||||
|
self.addSubnode(self.listNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func enqueueTransition(_ transition: MediaGroupsAlbumGridItemNodeTransition) {
|
||||||
|
self.enqueuedTransitions.append(transition)
|
||||||
|
|
||||||
|
if let _ = self.item {
|
||||||
|
while !self.enqueuedTransitions.isEmpty {
|
||||||
|
self.dequeueTransition()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func dequeueTransition() {
|
||||||
|
guard let _ = self.item, let transition = self.enqueuedTransitions.first else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.enqueuedTransitions.remove(at: 0)
|
||||||
|
|
||||||
|
var options = ListViewDeleteAndInsertOptions()
|
||||||
|
options.insert(.Synchronous)
|
||||||
|
|
||||||
|
self.listNode.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, scrollToItem: nil, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { _ in
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override func layoutForParams(_ params: ListViewItemLayoutParams, item: ListViewItem, previousItem: ListViewItem?, nextItem: ListViewItem?) {
|
||||||
|
if let item = self.item {
|
||||||
|
let makeLayout = self.asyncLayout()
|
||||||
|
let (nodeLayout, nodeApply) = makeLayout(item, params)
|
||||||
|
self.contentSize = nodeLayout.contentSize
|
||||||
|
self.insets = nodeLayout.insets
|
||||||
|
let _ = nodeApply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func asyncLayout() -> (_ item: MediaGroupsAlbumGridItem, _ params: ListViewItemLayoutParams) -> (ListViewItemNodeLayout, () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) {
|
||||||
|
return { [weak self] item, params in
|
||||||
|
let contentSize = CGSize(width: params.width, height: 220.0)
|
||||||
|
let nodeLayout = ListViewItemNodeLayout(contentSize: contentSize, insets: UIEdgeInsets())
|
||||||
|
|
||||||
|
return (nodeLayout, { [weak self] in
|
||||||
|
return (nil, { _ in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.item = item
|
||||||
|
strongSelf.layoutParams = params
|
||||||
|
|
||||||
|
let listInsets = UIEdgeInsets(top: 10.0, left: 0.0, bottom: 10.0, right: 0.0)
|
||||||
|
strongSelf.listNode.bounds = CGRect(x: 0.0, y: 0.0, width: contentSize.height, height: contentSize.width - params.leftInset - params.rightInset)
|
||||||
|
strongSelf.listNode.position = CGPoint(x: contentSize.width / 2.0, y: contentSize.height / 2.0)
|
||||||
|
strongSelf.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: CGSize(width: contentSize.height, height: contentSize.width), insets: listInsets, duration: 0.0, curve: .Default(duration: nil)), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||||
|
|
||||||
|
var entries: [MediaGroupsGridAlbumEntry] = []
|
||||||
|
var index: Int = 0
|
||||||
|
for collection in item.collections {
|
||||||
|
let result = PHAsset.fetchAssets(in: collection, options: nil)
|
||||||
|
if let firstItem = result.firstObject {
|
||||||
|
entries.append(MediaGroupsGridAlbumEntry(theme: item.presentationData.theme, index: index, collection: collection, firstItem: firstItem, count: presentationStringsFormattedNumber(Int32(result.count))))
|
||||||
|
index += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let previousEntries = strongSelf.entries ?? []
|
||||||
|
let transition = preparedTransition(action: { [weak item] collection in
|
||||||
|
item?.action(collection)
|
||||||
|
}, from: previousEntries, to: entries)
|
||||||
|
strongSelf.enqueueTransition(transition)
|
||||||
|
|
||||||
|
strongSelf.entries = entries
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||||
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration * 0.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||||
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false)
|
||||||
|
}
|
||||||
|
}
|
329
submodules/MediaPickerUI/Sources/MediaGroupsAlbumItem.swift
Normal file
329
submodules/MediaPickerUI/Sources/MediaGroupsAlbumItem.swift
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import Display
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import SwiftSignalKit
|
||||||
|
import TelegramPresentationData
|
||||||
|
import ItemListUI
|
||||||
|
import PresentationDataUtils
|
||||||
|
import AppBundle
|
||||||
|
|
||||||
|
class MediaGroupsAlbumItem: ListViewItem, ListViewItemWithHeader {
|
||||||
|
enum Icon {
|
||||||
|
case bursts
|
||||||
|
case panoramas
|
||||||
|
case screenshots
|
||||||
|
case selfPortraits
|
||||||
|
case slomoVideos
|
||||||
|
case timelapses
|
||||||
|
case videos
|
||||||
|
case animated
|
||||||
|
case depthEffect
|
||||||
|
case livePhotos
|
||||||
|
|
||||||
|
var image: UIImage? {
|
||||||
|
switch self {
|
||||||
|
case .bursts:
|
||||||
|
return UIImage(bundleImageName: "Chat/Attach Menu/Burst")
|
||||||
|
case .panoramas:
|
||||||
|
return UIImage(bundleImageName: "Chat/Attach Menu/Panorama")
|
||||||
|
case .screenshots:
|
||||||
|
return UIImage(bundleImageName: "Chat/Attach Menu/Screenshot")
|
||||||
|
case .selfPortraits:
|
||||||
|
return UIImage(bundleImageName: "Chat/Attach Menu/Selfie")
|
||||||
|
case .slomoVideos:
|
||||||
|
return UIImage(bundleImageName: "Chat/Attach Menu/SloMo")
|
||||||
|
case .timelapses:
|
||||||
|
return UIImage(bundleImageName: "Chat/Attach Menu/Timelapse")
|
||||||
|
case .videos:
|
||||||
|
return UIImage(bundleImageName: "Chat/Attach Menu/Video")
|
||||||
|
case .animated:
|
||||||
|
return UIImage(bundleImageName: "Chat/Attach Menu/Animated")
|
||||||
|
case .depthEffect:
|
||||||
|
return UIImage(bundleImageName: "Chat/Attach Menu/Portrait")
|
||||||
|
case .livePhotos:
|
||||||
|
return UIImage(bundleImageName: "Chat/Attach Menu/LivePhoto")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let presentationData: ItemListPresentationData
|
||||||
|
let title: String
|
||||||
|
let count: String
|
||||||
|
let icon: Icon?
|
||||||
|
let action: () -> Void
|
||||||
|
let header: ListViewItemHeader? = nil
|
||||||
|
|
||||||
|
init(presentationData: ItemListPresentationData, title: String, count: String, icon: Icon?, action: @escaping () -> Void) {
|
||||||
|
self.presentationData = presentationData
|
||||||
|
self.title = title
|
||||||
|
self.count = count
|
||||||
|
self.icon = icon
|
||||||
|
self.action = action
|
||||||
|
}
|
||||||
|
|
||||||
|
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||||
|
async {
|
||||||
|
let node = MediaGroupsAlbumItemNode()
|
||||||
|
let (first, last) = MediaGroupsAlbumItem.mergeType(item: self, previousItem: previousItem, nextItem: nextItem)
|
||||||
|
let (layout, apply) = node.asyncLayout()(self, params, first, last)
|
||||||
|
|
||||||
|
node.contentSize = layout.contentSize
|
||||||
|
node.insets = layout.insets
|
||||||
|
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
completion(node, {
|
||||||
|
return (nil, { _ in apply() })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
if let nodeValue = node() as? MediaGroupsAlbumItemNode {
|
||||||
|
let makeLayout = nodeValue.asyncLayout()
|
||||||
|
|
||||||
|
async {
|
||||||
|
let (first, last) = MediaGroupsAlbumItem.mergeType(item: self, previousItem: previousItem, nextItem: nextItem)
|
||||||
|
let (layout, apply) = makeLayout(self, params, first, last)
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
completion(layout, { _ in
|
||||||
|
apply()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var selectable: Bool = true
|
||||||
|
|
||||||
|
public func selected(listView: ListView){
|
||||||
|
self.action()
|
||||||
|
|
||||||
|
listView.clearHighlightAnimated(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func mergeType(item: MediaGroupsAlbumItem, previousItem: ListViewItem?, nextItem: ListViewItem?) -> (first: Bool, last: Bool) {
|
||||||
|
var first = false
|
||||||
|
var last = false
|
||||||
|
|
||||||
|
if let previousItem = previousItem, !(previousItem is MediaGroupsAlbumItem) {
|
||||||
|
first = true
|
||||||
|
}
|
||||||
|
if nextItem == nil {
|
||||||
|
last = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return (first, last)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MediaGroupsAlbumItemNode: ListViewItemNode {
|
||||||
|
private let backgroundNode: ASDisplayNode
|
||||||
|
private let topStripeNode: ASDisplayNode
|
||||||
|
private let bottomStripeNode: ASDisplayNode
|
||||||
|
private let highlightedBackgroundNode: ASDisplayNode
|
||||||
|
|
||||||
|
private let iconNode: ASImageNode
|
||||||
|
private let titleNode: TextNode
|
||||||
|
private let countNode: TextNode
|
||||||
|
private let arrowNode: ASImageNode
|
||||||
|
|
||||||
|
private let activateArea: AccessibilityAreaNode
|
||||||
|
|
||||||
|
private var item: MediaGroupsAlbumItem?
|
||||||
|
|
||||||
|
init() {
|
||||||
|
self.backgroundNode = ASDisplayNode()
|
||||||
|
self.backgroundNode.isLayerBacked = true
|
||||||
|
self.backgroundNode.backgroundColor = .white
|
||||||
|
|
||||||
|
self.topStripeNode = ASDisplayNode()
|
||||||
|
self.topStripeNode.isLayerBacked = true
|
||||||
|
|
||||||
|
self.bottomStripeNode = ASDisplayNode()
|
||||||
|
self.bottomStripeNode.isLayerBacked = true
|
||||||
|
|
||||||
|
self.titleNode = TextNode()
|
||||||
|
self.titleNode.isUserInteractionEnabled = false
|
||||||
|
self.titleNode.contentMode = .left
|
||||||
|
self.titleNode.contentsScale = UIScreen.main.scale
|
||||||
|
|
||||||
|
self.iconNode = ASImageNode()
|
||||||
|
self.iconNode.isLayerBacked = true
|
||||||
|
self.iconNode.displayWithoutProcessing = true
|
||||||
|
self.iconNode.displaysAsynchronously = false
|
||||||
|
|
||||||
|
self.countNode = TextNode()
|
||||||
|
self.countNode.isUserInteractionEnabled = false
|
||||||
|
self.countNode.contentMode = .left
|
||||||
|
self.countNode.contentsScale = UIScreen.main.scale
|
||||||
|
|
||||||
|
self.arrowNode = ASImageNode()
|
||||||
|
self.arrowNode.isLayerBacked = true
|
||||||
|
self.arrowNode.displayWithoutProcessing = true
|
||||||
|
self.arrowNode.displaysAsynchronously = false
|
||||||
|
|
||||||
|
self.highlightedBackgroundNode = ASDisplayNode()
|
||||||
|
self.highlightedBackgroundNode.isLayerBacked = true
|
||||||
|
|
||||||
|
self.activateArea = AccessibilityAreaNode()
|
||||||
|
|
||||||
|
super.init(layerBacked: false, dynamicBounce: false)
|
||||||
|
|
||||||
|
self.addSubnode(self.iconNode)
|
||||||
|
self.addSubnode(self.titleNode)
|
||||||
|
self.addSubnode(self.countNode)
|
||||||
|
self.addSubnode(self.arrowNode)
|
||||||
|
self.addSubnode(self.activateArea)
|
||||||
|
|
||||||
|
self.activateArea.activate = { [weak self] in
|
||||||
|
self?.item?.action()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func asyncLayout() -> (_ item: MediaGroupsAlbumItem, _ params: ListViewItemLayoutParams, _ first: Bool, _ last: Bool) -> (ListViewItemNodeLayout, () -> Void) {
|
||||||
|
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||||
|
let makeCountLayout = TextNode.asyncLayout(self.countNode)
|
||||||
|
let currentItem = self.item
|
||||||
|
|
||||||
|
return { item, params, first, last in
|
||||||
|
var updatedTheme: PresentationTheme?
|
||||||
|
|
||||||
|
if currentItem?.presentationData.theme !== item.presentationData.theme {
|
||||||
|
updatedTheme = item.presentationData.theme
|
||||||
|
}
|
||||||
|
|
||||||
|
let titleFont = Font.regular(21.0)
|
||||||
|
let countFont = Font.regular(17.0)
|
||||||
|
|
||||||
|
let leftInset: CGFloat = 60.0 + params.leftInset
|
||||||
|
|
||||||
|
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: titleFont, textColor: item.presentationData.theme.list.itemAccentColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - 10.0 - leftInset - params.rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
|
let (countLayout, countApply) = makeCountLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.count, font: countFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - 10.0 - leftInset - params.rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
|
let contentHeight: CGFloat = 48.0
|
||||||
|
|
||||||
|
let contentSize = CGSize(width: params.width, height: contentHeight)
|
||||||
|
let insets = UIEdgeInsets()
|
||||||
|
let separatorHeight = UIScreenPixel
|
||||||
|
|
||||||
|
let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
|
||||||
|
|
||||||
|
return (layout, { [weak self] in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.item = item
|
||||||
|
|
||||||
|
strongSelf.activateArea.accessibilityLabel = item.title
|
||||||
|
strongSelf.activateArea.frame = CGRect(origin: CGPoint(x: params.leftInset, y: 0.0), size: CGSize(width: layout.contentSize.width - params.leftInset - params.rightInset, height: layout.contentSize.height))
|
||||||
|
|
||||||
|
if let _ = updatedTheme {
|
||||||
|
strongSelf.topStripeNode.backgroundColor = item.presentationData.theme.list.itemPlainSeparatorColor
|
||||||
|
strongSelf.bottomStripeNode.backgroundColor = item.presentationData.theme.list.itemPlainSeparatorColor
|
||||||
|
strongSelf.backgroundNode.backgroundColor = item.presentationData.theme.list.plainBackgroundColor
|
||||||
|
strongSelf.highlightedBackgroundNode.backgroundColor = item.presentationData.theme.list.itemHighlightedBackgroundColor
|
||||||
|
|
||||||
|
strongSelf.iconNode.image = generateTintedImage(image: item.icon?.image, color: item.presentationData.theme.list.itemAccentColor)
|
||||||
|
strongSelf.arrowNode.image = PresentationResourcesItemList.disclosureArrowImage(item.presentationData.theme)
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.addSubnode(strongSelf.activateArea)
|
||||||
|
|
||||||
|
let _ = titleApply()
|
||||||
|
let _ = countApply()
|
||||||
|
|
||||||
|
let titleOffset = leftInset
|
||||||
|
let hideBottomStripe: Bool = last
|
||||||
|
|
||||||
|
if let image = strongSelf.iconNode.image {
|
||||||
|
strongSelf.iconNode.frame = CGRect(origin: CGPoint(x: params.leftInset + 14.0, y: floorToScreenPixels((contentSize.height - image.size.height) / 2.0)), size: image.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strongSelf.backgroundNode.supernode == nil {
|
||||||
|
strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0)
|
||||||
|
}
|
||||||
|
if strongSelf.topStripeNode.supernode == nil {
|
||||||
|
strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1)
|
||||||
|
}
|
||||||
|
if strongSelf.bottomStripeNode.supernode == nil {
|
||||||
|
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
||||||
|
|
||||||
|
strongSelf.topStripeNode.isHidden = true
|
||||||
|
strongSelf.bottomStripeNode.isHidden = hideBottomStripe
|
||||||
|
|
||||||
|
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight))
|
||||||
|
|
||||||
|
strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: titleOffset, y: floorToScreenPixels((contentSize.height - titleLayout.size.height) / 2.0) + 1.0), size: titleLayout.size)
|
||||||
|
|
||||||
|
if let arrowSize = strongSelf.arrowNode.image?.size {
|
||||||
|
strongSelf.arrowNode.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - arrowSize.width - 12.0, y: floorToScreenPixels((contentSize.height - arrowSize.height) / 2.0)), size: arrowSize)
|
||||||
|
|
||||||
|
strongSelf.countNode.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - countLayout.size.width - arrowSize.width - 12.0 - 2.0, y: floorToScreenPixels((contentSize.height - countLayout.size.height) / 2.0) + 1.0), size: countLayout.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: contentSize.height + UIScreenPixel + UIScreenPixel))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
|
||||||
|
super.setHighlighted(highlighted, at: point, animated: animated)
|
||||||
|
|
||||||
|
if highlighted {
|
||||||
|
self.highlightedBackgroundNode.alpha = 1.0
|
||||||
|
if self.highlightedBackgroundNode.supernode == nil {
|
||||||
|
var anchorNode: ASDisplayNode?
|
||||||
|
if self.bottomStripeNode.supernode != nil {
|
||||||
|
anchorNode = self.bottomStripeNode
|
||||||
|
} else if self.topStripeNode.supernode != nil {
|
||||||
|
anchorNode = self.topStripeNode
|
||||||
|
} else if self.backgroundNode.supernode != nil {
|
||||||
|
anchorNode = self.backgroundNode
|
||||||
|
}
|
||||||
|
if let anchorNode = anchorNode {
|
||||||
|
self.insertSubnode(self.highlightedBackgroundNode, aboveSubnode: anchorNode)
|
||||||
|
} else {
|
||||||
|
self.addSubnode(self.highlightedBackgroundNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if self.highlightedBackgroundNode.supernode != nil {
|
||||||
|
if animated {
|
||||||
|
self.highlightedBackgroundNode.layer.animateAlpha(from: self.highlightedBackgroundNode.alpha, to: 0.0, duration: 0.4, completion: { [weak self] completed in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if completed {
|
||||||
|
strongSelf.highlightedBackgroundNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.highlightedBackgroundNode.alpha = 0.0
|
||||||
|
} else {
|
||||||
|
self.highlightedBackgroundNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||||
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||||
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func headers() -> [ListViewItemHeader]? {
|
||||||
|
if let item = self.item {
|
||||||
|
return item.header.flatMap { [$0] }
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
110
submodules/MediaPickerUI/Sources/MediaGroupsHeaderItem.swift
Normal file
110
submodules/MediaPickerUI/Sources/MediaGroupsHeaderItem.swift
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import Display
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import SwiftSignalKit
|
||||||
|
import TelegramPresentationData
|
||||||
|
import ItemListUI
|
||||||
|
|
||||||
|
final class MediaGroupsHeaderItem: ListViewItem {
|
||||||
|
let presentationData: ItemListPresentationData
|
||||||
|
let title: String
|
||||||
|
|
||||||
|
public init(presentationData: ItemListPresentationData, title: String) {
|
||||||
|
self.presentationData = presentationData
|
||||||
|
self.title = title
|
||||||
|
}
|
||||||
|
|
||||||
|
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||||
|
async {
|
||||||
|
let node = MediaGroupsHeaderItemNode()
|
||||||
|
let makeLayout = node.asyncLayout()
|
||||||
|
let (nodeLayout, nodeApply) = makeLayout(self, params)
|
||||||
|
node.contentSize = nodeLayout.contentSize
|
||||||
|
node.insets = nodeLayout.insets
|
||||||
|
|
||||||
|
completion(node, nodeApply)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
if let nodeValue = node() as? MediaGroupsHeaderItemNode {
|
||||||
|
let layout = nodeValue.asyncLayout()
|
||||||
|
async {
|
||||||
|
let (nodeLayout, apply) = layout(self, params)
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
completion(nodeLayout, { info in
|
||||||
|
apply().1(info)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var selectable: Bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private let titleFont = Font.bold(22.0)
|
||||||
|
|
||||||
|
private class MediaGroupsHeaderItemNode: ListViewItemNode {
|
||||||
|
private let titleNode: TextNode
|
||||||
|
|
||||||
|
private var item: MediaGroupsHeaderItem?
|
||||||
|
private var layoutParams: ListViewItemLayoutParams?
|
||||||
|
|
||||||
|
init() {
|
||||||
|
self.titleNode = TextNode()
|
||||||
|
|
||||||
|
super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false)
|
||||||
|
|
||||||
|
self.addSubnode(self.titleNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func layoutForParams(_ params: ListViewItemLayoutParams, item: ListViewItem, previousItem: ListViewItem?, nextItem: ListViewItem?) {
|
||||||
|
if let item = self.item {
|
||||||
|
let makeLayout = self.asyncLayout()
|
||||||
|
let (nodeLayout, nodeApply) = makeLayout(item, params)
|
||||||
|
self.contentSize = nodeLayout.contentSize
|
||||||
|
self.insets = nodeLayout.insets
|
||||||
|
let _ = nodeApply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func asyncLayout() -> (_ item: MediaGroupsHeaderItem, _ params: ListViewItemLayoutParams) -> (ListViewItemNodeLayout, () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) {
|
||||||
|
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||||
|
|
||||||
|
|
||||||
|
return { [weak self] item, params in
|
||||||
|
let titleString = NSAttributedString(string: item.title, font: titleFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor)
|
||||||
|
|
||||||
|
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - 16.0, height: 100.0), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
|
let contentSize = CGSize(width: params.width, height: 45.0)
|
||||||
|
let nodeLayout = ListViewItemNodeLayout(contentSize: contentSize, insets: UIEdgeInsets())
|
||||||
|
|
||||||
|
return (nodeLayout, { [weak self] in
|
||||||
|
return (nil, { _ in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.item = item
|
||||||
|
strongSelf.layoutParams = params
|
||||||
|
|
||||||
|
let _ = titleApply()
|
||||||
|
strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: params.leftInset + 17.0, y: floor((nodeLayout.contentSize.height - titleLayout.size.height) / 2.0) + 2.0), size: titleLayout.size)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||||
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration * 0.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||||
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false)
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,401 @@
|
|||||||
//
|
|
||||||
// MediaGroupsScreen.swift
|
|
||||||
// _idx_TelegramUI_F082088E_ios_min9.0
|
|
||||||
//
|
|
||||||
// Created by Ilya Laktyushin on 22.02.2022.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import Display
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import Postbox
|
||||||
|
import TelegramCore
|
||||||
|
import SwiftSignalKit
|
||||||
|
import AccountContext
|
||||||
|
import TelegramPresentationData
|
||||||
|
import TelegramUIPreferences
|
||||||
|
import MergeLists
|
||||||
|
import Photos
|
||||||
|
import LegacyComponents
|
||||||
|
import AttachmentUI
|
||||||
|
import ItemListUI
|
||||||
|
|
||||||
|
private enum MediaGroupsEntry: Comparable, Identifiable {
|
||||||
|
enum StableId: Hashable {
|
||||||
|
case albumsHeader
|
||||||
|
case albums
|
||||||
|
case smartAlbumsHeader
|
||||||
|
case smartAlbum(String)
|
||||||
|
}
|
||||||
|
|
||||||
|
case albumsHeader(PresentationTheme, String)
|
||||||
|
case albums(PresentationTheme, [PHAssetCollection])
|
||||||
|
case smartAlbumsHeader(PresentationTheme, String)
|
||||||
|
case smartAlbum(PresentationTheme, Int, PHAssetCollection, Int)
|
||||||
|
|
||||||
|
var stableId: StableId {
|
||||||
|
switch self {
|
||||||
|
case .albumsHeader:
|
||||||
|
return .albumsHeader
|
||||||
|
case .albums:
|
||||||
|
return .albums
|
||||||
|
case .smartAlbumsHeader:
|
||||||
|
return .smartAlbumsHeader
|
||||||
|
case let .smartAlbum(_, _, album, _):
|
||||||
|
return .smartAlbum(album.localIdentifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func ==(lhs: MediaGroupsEntry, rhs: MediaGroupsEntry) -> Bool {
|
||||||
|
switch lhs {
|
||||||
|
case let .albumsHeader(lhsTheme, lhsText):
|
||||||
|
if case let .albumsHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case let .albums(lhsTheme, lhsAssetCollections):
|
||||||
|
if case let .albums(rhsTheme, rhsAssetCollections) = rhs, lhsTheme === rhsTheme, lhsAssetCollections == rhsAssetCollections {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case let .smartAlbumsHeader(lhsTheme, lhsText):
|
||||||
|
if case let .smartAlbumsHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case let .smartAlbum(lhsTheme, lhsIndex, lhsAssetCollection, lhsCount):
|
||||||
|
if case let .smartAlbum(rhsTheme, rhsIndex, rhsAssetCollection, rhsCount) = rhs, lhsTheme === rhsTheme, lhsIndex == rhsIndex, lhsAssetCollection == rhsAssetCollection, lhsCount == rhsCount {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var sortId: Int {
|
||||||
|
switch self {
|
||||||
|
case .albumsHeader:
|
||||||
|
return 0
|
||||||
|
case .albums:
|
||||||
|
return 1
|
||||||
|
case .smartAlbumsHeader:
|
||||||
|
return 2
|
||||||
|
case let .smartAlbum(_, index, _, _):
|
||||||
|
return 3 + index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func <(lhs: MediaGroupsEntry, rhs: MediaGroupsEntry) -> Bool {
|
||||||
|
return lhs.sortId < rhs.sortId
|
||||||
|
}
|
||||||
|
|
||||||
|
func item(presentationData: PresentationData, openGroup: @escaping (PHAssetCollection) -> Void) -> ListViewItem {
|
||||||
|
switch self {
|
||||||
|
case let .albumsHeader(_, text), let .smartAlbumsHeader(_, text):
|
||||||
|
return MediaGroupsHeaderItem(presentationData: ItemListPresentationData(presentationData), title: text)
|
||||||
|
case let .albums(_, collections):
|
||||||
|
return MediaGroupsAlbumGridItem(presentationData: ItemListPresentationData(presentationData), collections: collections, action: { collection in
|
||||||
|
openGroup(collection)
|
||||||
|
})
|
||||||
|
case let .smartAlbum(_, _, collection, count):
|
||||||
|
let title = collection.localizedTitle ?? ""
|
||||||
|
|
||||||
|
let count = presentationStringsFormattedNumber(Int32(count), presentationData.dateTimeFormat.groupingSeparator)
|
||||||
|
var icon: MediaGroupsAlbumItem.Icon?
|
||||||
|
switch collection.assetCollectionSubtype {
|
||||||
|
case .smartAlbumAnimated:
|
||||||
|
icon = .animated
|
||||||
|
case .smartAlbumBursts:
|
||||||
|
icon = .bursts
|
||||||
|
case .smartAlbumDepthEffect:
|
||||||
|
icon = .selfPortraits
|
||||||
|
case .smartAlbumLivePhotos:
|
||||||
|
icon = .depthEffect
|
||||||
|
case .smartAlbumPanoramas:
|
||||||
|
icon = .panoramas
|
||||||
|
case .smartAlbumScreenshots:
|
||||||
|
icon = .screenshots
|
||||||
|
case .smartAlbumSelfPortraits:
|
||||||
|
icon = .selfPortraits
|
||||||
|
case .smartAlbumSlomoVideos:
|
||||||
|
icon = .slomoVideos
|
||||||
|
case .smartAlbumTimelapses:
|
||||||
|
icon = .timelapses
|
||||||
|
case .smartAlbumVideos:
|
||||||
|
icon = .videos
|
||||||
|
default:
|
||||||
|
icon = nil
|
||||||
|
}
|
||||||
|
return MediaGroupsAlbumItem(presentationData: ItemListPresentationData(presentationData), title: title, count: count, icon: icon, action: {
|
||||||
|
openGroup(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct MediaGroupsTransition {
|
||||||
|
let deletions: [ListViewDeleteItem]
|
||||||
|
let insertions: [ListViewInsertItem]
|
||||||
|
let updates: [ListViewUpdateItem]
|
||||||
|
}
|
||||||
|
|
||||||
|
private func preparedTransition(from fromEntries: [MediaGroupsEntry], to toEntries: [MediaGroupsEntry], presentationData: PresentationData, openGroup: @escaping (PHAssetCollection) -> Void) -> MediaGroupsTransition {
|
||||||
|
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||||
|
|
||||||
|
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||||
|
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(presentationData: presentationData, openGroup: openGroup), directionHint: nil) }
|
||||||
|
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(presentationData: presentationData, openGroup: openGroup), directionHint: nil) }
|
||||||
|
|
||||||
|
return MediaGroupsTransition(deletions: deletions, insertions: insertions, updates: updates)
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class MediaGroupsScreen: ViewController {
|
||||||
|
private let context: AccountContext
|
||||||
|
private var presentationData: PresentationData
|
||||||
|
private var presentationDataDisposable: Disposable?
|
||||||
|
private let mediaAssetsContext: MediaAssetsContext
|
||||||
|
private let openGroup: (PHAssetCollection) -> Void
|
||||||
|
|
||||||
|
private class Node: ViewControllerTracingNode {
|
||||||
|
struct State {
|
||||||
|
let albums: PHFetchResult<PHAssetCollection>
|
||||||
|
let smartAlbums: PHFetchResult<PHAssetCollection>
|
||||||
|
}
|
||||||
|
|
||||||
|
private weak var controller: MediaGroupsScreen?
|
||||||
|
private var presentationData: PresentationData
|
||||||
|
|
||||||
|
private let containerNode: ASDisplayNode
|
||||||
|
private let listNode: ListView
|
||||||
|
|
||||||
|
private var nextStableId: Int = 1
|
||||||
|
private var currentEntries: [MediaGroupsEntry] = []
|
||||||
|
private var enqueuedTransactions: [MediaGroupsTransition] = []
|
||||||
|
private var state: State?
|
||||||
|
|
||||||
|
private var itemsDisposable: Disposable?
|
||||||
|
|
||||||
|
private var didSetReady = false
|
||||||
|
private let _ready = Promise<Bool>()
|
||||||
|
var ready: Promise<Bool> {
|
||||||
|
return self._ready
|
||||||
|
}
|
||||||
|
|
||||||
|
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||||
|
|
||||||
|
init(controller: MediaGroupsScreen) {
|
||||||
|
self.controller = controller
|
||||||
|
self.presentationData = controller.presentationData
|
||||||
|
|
||||||
|
self.containerNode = ASDisplayNode()
|
||||||
|
self.listNode = ListView()
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.containerNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||||
|
|
||||||
|
self.addSubnode(self.containerNode)
|
||||||
|
self.containerNode.addSubnode(self.listNode)
|
||||||
|
|
||||||
|
let updatedState = combineLatest(queue: Queue.mainQueue(), controller.mediaAssetsContext.fetchAssetsCollections(.album), controller.mediaAssetsContext.fetchAssetsCollections(.smartAlbum))
|
||||||
|
self.itemsDisposable = (updatedState
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] albums, smartAlbums in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.updateState(State(albums: albums, smartAlbums: smartAlbums))
|
||||||
|
})
|
||||||
|
|
||||||
|
self.listNode.beganInteractiveDragging = { [weak self] _ in
|
||||||
|
self?.view.window?.endEditing(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.itemsDisposable?.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
|
let result = super.hitTest(point, with: event)
|
||||||
|
if result == self.view {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateState(_ state: State) {
|
||||||
|
self.state = state
|
||||||
|
|
||||||
|
var entries: [MediaGroupsEntry] = []
|
||||||
|
|
||||||
|
var albums: [PHAssetCollection] = []
|
||||||
|
entries.append(.albumsHeader(self.presentationData.theme, self.presentationData.strings.Attachment_MyAlbums))
|
||||||
|
state.smartAlbums.enumerateObjects { collection, _, _ in
|
||||||
|
if [.smartAlbumUserLibrary, .smartAlbumFavorites].contains(collection.assetCollectionSubtype) {
|
||||||
|
albums.append(collection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.albums.enumerateObjects { collection, _, _ in
|
||||||
|
albums.append(collection)
|
||||||
|
}
|
||||||
|
entries.append(.albums(self.presentationData.theme, albums))
|
||||||
|
|
||||||
|
let smartAlbumsHeaderIndex = entries.count
|
||||||
|
|
||||||
|
var addedSmartAlbum = false
|
||||||
|
state.smartAlbums.enumerateObjects { collection, index, _ in
|
||||||
|
var supportedAlbums: [PHAssetCollectionSubtype] = [
|
||||||
|
.smartAlbumBursts,
|
||||||
|
.smartAlbumPanoramas,
|
||||||
|
.smartAlbumScreenshots,
|
||||||
|
.smartAlbumSelfPortraits,
|
||||||
|
.smartAlbumSlomoVideos,
|
||||||
|
.smartAlbumTimelapses,
|
||||||
|
.smartAlbumVideos
|
||||||
|
]
|
||||||
|
if #available(iOS 11, *) {
|
||||||
|
supportedAlbums.append(.smartAlbumAnimated)
|
||||||
|
supportedAlbums.append(.smartAlbumDepthEffect)
|
||||||
|
supportedAlbums.append(.smartAlbumLivePhotos)
|
||||||
|
}
|
||||||
|
if supportedAlbums.contains(collection.assetCollectionSubtype) {
|
||||||
|
let result = PHAsset.fetchAssets(in: collection, options: nil)
|
||||||
|
if result.count > 0 {
|
||||||
|
addedSmartAlbum = true
|
||||||
|
entries.append(.smartAlbum(self.presentationData.theme, index, collection, result.count))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if addedSmartAlbum {
|
||||||
|
entries.insert(.smartAlbumsHeader(self.presentationData.theme, self.presentationData.strings.Attachment_MediaTypes), at: smartAlbumsHeaderIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
let previousEntries = self.currentEntries
|
||||||
|
self.currentEntries = entries
|
||||||
|
|
||||||
|
let transaction = preparedTransition(from: previousEntries, to: entries, presentationData: self.presentationData, openGroup: { [weak self] collection in
|
||||||
|
self?.view.window?.endEditing(true)
|
||||||
|
self?.controller?.openGroup(collection)
|
||||||
|
})
|
||||||
|
self.enqueueTransaction(transaction)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func updatePresentationData(_ presentationData: PresentationData) {
|
||||||
|
self.presentationData = presentationData
|
||||||
|
|
||||||
|
self.backgroundColor = presentationData.theme.list.plainBackgroundColor
|
||||||
|
}
|
||||||
|
|
||||||
|
private func enqueueTransaction(_ transaction: MediaGroupsTransition) {
|
||||||
|
self.enqueuedTransactions.append(transaction)
|
||||||
|
|
||||||
|
if let _ = self.validLayout {
|
||||||
|
while !self.enqueuedTransactions.isEmpty {
|
||||||
|
self.dequeueTransaction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func dequeueTransaction() {
|
||||||
|
if self.enqueuedTransactions.isEmpty {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let transaction = self.enqueuedTransactions.removeFirst()
|
||||||
|
|
||||||
|
let options = ListViewDeleteAndInsertOptions()
|
||||||
|
|
||||||
|
self.listNode.transaction(deleteIndices: transaction.deletions, insertIndicesAndItems: transaction.insertions, updateIndicesAndItems: transaction.updates, options: options, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { [weak self] _ in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if !strongSelf.didSetReady {
|
||||||
|
strongSelf.didSetReady = true
|
||||||
|
strongSelf._ready.set(.single(true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func scrollToTop() {
|
||||||
|
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||||
|
}
|
||||||
|
|
||||||
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
|
let firstTime = self.validLayout == nil
|
||||||
|
self.validLayout = (layout, navigationBarHeight)
|
||||||
|
|
||||||
|
transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: navigationBarHeight + 2.0), size: CGSize(width: layout.size.width, height: layout.size.height - navigationBarHeight - 2.0)))
|
||||||
|
|
||||||
|
let size = layout.size
|
||||||
|
let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition)
|
||||||
|
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: size, insets: UIEdgeInsets(top: 7.0, left: layout.safeInsets.left, bottom: layout.intrinsicInsets.bottom + 50.0, right: layout.safeInsets.right), headerInsets: UIEdgeInsets(), scrollIndicatorInsets: UIEdgeInsets(), duration: duration, curve: curve), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||||
|
transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
|
if firstTime {
|
||||||
|
self.dequeueTransaction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var validLayout: ContainerViewLayout?
|
||||||
|
|
||||||
|
private var controllerNode: Node {
|
||||||
|
return self.displayNode as! Node
|
||||||
|
}
|
||||||
|
|
||||||
|
private let _ready = Promise<Bool>()
|
||||||
|
override public var ready: Promise<Bool> {
|
||||||
|
return self._ready
|
||||||
|
}
|
||||||
|
|
||||||
|
init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, mediaAssetsContext: MediaAssetsContext, openGroup: @escaping (PHAssetCollection) -> Void) {
|
||||||
|
self.context = context
|
||||||
|
self.presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
self.mediaAssetsContext = mediaAssetsContext
|
||||||
|
self.openGroup = openGroup
|
||||||
|
|
||||||
|
super.init(navigationBarPresentationData: nil)
|
||||||
|
|
||||||
|
self.statusBar.statusBarStyle = .Ignore
|
||||||
|
|
||||||
|
self.presentationDataDisposable = ((updatedPresentationData?.signal ?? context.sharedContext.presentationData)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
||||||
|
if let strongSelf = self {
|
||||||
|
let previousTheme = strongSelf.presentationData.theme
|
||||||
|
let previousStrings = strongSelf.presentationData.strings
|
||||||
|
|
||||||
|
strongSelf.presentationData = presentationData
|
||||||
|
|
||||||
|
if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings {
|
||||||
|
strongSelf.controllerNode.updatePresentationData(presentationData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
self.scrollToTop = { [weak self] in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.controllerNode.scrollToTop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
required init(coder aDecoder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.presentationDataDisposable?.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func loadDisplayNode() {
|
||||||
|
self.displayNode = Node(controller: self)
|
||||||
|
|
||||||
|
self._ready.set(self.controllerNode.ready.get())
|
||||||
|
|
||||||
|
super.displayNodeDidLoad()
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
|
super.containerLayoutUpdated(layout, transition: transition)
|
||||||
|
|
||||||
|
self.validLayout = layout
|
||||||
|
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -9,6 +9,13 @@ import SolidRoundedButtonNode
|
|||||||
import PresentationDataUtils
|
import PresentationDataUtils
|
||||||
|
|
||||||
final class MediaPickerPlaceholderNode: ASDisplayNode {
|
final class MediaPickerPlaceholderNode: ASDisplayNode {
|
||||||
|
enum Content {
|
||||||
|
case intro
|
||||||
|
case bannedSendMedia(String)
|
||||||
|
}
|
||||||
|
|
||||||
|
private let content: Content
|
||||||
|
|
||||||
private var animationNode: AnimatedStickerNode
|
private var animationNode: AnimatedStickerNode
|
||||||
private let titleNode: ImmediateTextNode
|
private let titleNode: ImmediateTextNode
|
||||||
private let textNode: ImmediateTextNode
|
private let textNode: ImmediateTextNode
|
||||||
@ -22,9 +29,22 @@ final class MediaPickerPlaceholderNode: ASDisplayNode {
|
|||||||
var settingsPressed: () -> Void = {}
|
var settingsPressed: () -> Void = {}
|
||||||
var cameraPressed: () -> Void = {}
|
var cameraPressed: () -> Void = {}
|
||||||
|
|
||||||
override init() {
|
init(content: Content) {
|
||||||
|
self.content = content
|
||||||
|
|
||||||
|
let name: String
|
||||||
|
let playbackMode: AnimatedStickerPlaybackMode
|
||||||
|
switch content {
|
||||||
|
case .intro:
|
||||||
|
name = "Photos"
|
||||||
|
playbackMode = .loop
|
||||||
|
case .bannedSendMedia:
|
||||||
|
name = "Banned"
|
||||||
|
playbackMode = .once
|
||||||
|
}
|
||||||
|
|
||||||
self.animationNode = AnimatedStickerNode()
|
self.animationNode = AnimatedStickerNode()
|
||||||
self.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: "Files"), width: 320, height: 320, playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
|
self.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: name), width: 320, height: 320, playbackMode: playbackMode, mode: .direct(cachePathPrefix: nil))
|
||||||
self.animationNode.visibility = true
|
self.animationNode.visibility = true
|
||||||
|
|
||||||
self.titleNode = ImmediateTextNode()
|
self.titleNode = ImmediateTextNode()
|
||||||
@ -54,33 +74,36 @@ final class MediaPickerPlaceholderNode: ASDisplayNode {
|
|||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.addSubnode(self.animationNode)
|
self.addSubnode(self.animationNode)
|
||||||
self.addSubnode(self.titleNode)
|
|
||||||
self.addSubnode(self.textNode)
|
self.addSubnode(self.textNode)
|
||||||
self.addSubnode(self.buttonNode)
|
|
||||||
|
|
||||||
self.addSubnode(self.cameraButtonNode)
|
if case .intro = self.content {
|
||||||
self.cameraButtonNode.addSubnode(self.cameraTextNode)
|
self.addSubnode(self.titleNode)
|
||||||
self.cameraButtonNode.addSubnode(self.cameraIconNode)
|
self.addSubnode(self.buttonNode)
|
||||||
|
|
||||||
self.cameraButtonNode.highligthedChanged = { [weak self] highlighted in
|
self.addSubnode(self.cameraButtonNode)
|
||||||
if let strongSelf = self {
|
self.cameraButtonNode.addSubnode(self.cameraTextNode)
|
||||||
if highlighted {
|
self.cameraButtonNode.addSubnode(self.cameraIconNode)
|
||||||
strongSelf.cameraTextNode.layer.removeAnimation(forKey: "opacity")
|
|
||||||
strongSelf.cameraTextNode.alpha = 0.4
|
self.cameraButtonNode.highligthedChanged = { [weak self] highlighted in
|
||||||
strongSelf.cameraIconNode.layer.removeAnimation(forKey: "opacity")
|
if let strongSelf = self {
|
||||||
strongSelf.cameraIconNode.alpha = 0.4
|
if highlighted {
|
||||||
} else {
|
strongSelf.cameraTextNode.layer.removeAnimation(forKey: "opacity")
|
||||||
strongSelf.cameraTextNode.alpha = 1.0
|
strongSelf.cameraTextNode.alpha = 0.4
|
||||||
strongSelf.cameraTextNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
strongSelf.cameraIconNode.layer.removeAnimation(forKey: "opacity")
|
||||||
strongSelf.cameraIconNode.alpha = 1.0
|
strongSelf.cameraIconNode.alpha = 0.4
|
||||||
strongSelf.cameraIconNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
} else {
|
||||||
|
strongSelf.cameraTextNode.alpha = 1.0
|
||||||
|
strongSelf.cameraTextNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
||||||
|
strongSelf.cameraIconNode.alpha = 1.0
|
||||||
|
strongSelf.cameraIconNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
self.cameraButtonNode.addTarget(self, action: #selector(self.cameraButtonPressed), forControlEvents: .touchUpInside)
|
||||||
self.cameraButtonNode.addTarget(self, action: #selector(self.cameraButtonPressed), forControlEvents: .touchUpInside)
|
|
||||||
|
self.buttonNode.pressed = { [weak self] in
|
||||||
self.buttonNode.pressed = { [weak self] in
|
self?.settingsPressed()
|
||||||
self?.settingsPressed()
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,20 +117,22 @@ final class MediaPickerPlaceholderNode: ASDisplayNode {
|
|||||||
let themeUpdated = self.theme != theme
|
let themeUpdated = self.theme != theme
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
|
|
||||||
|
var imageSize = CGSize(width: 144.0, height: 144.0)
|
||||||
var insets = layout.insets(options: [])
|
var insets = layout.insets(options: [])
|
||||||
insets.top += -160.0
|
if layout.size.width == 460.0 {
|
||||||
|
insets.top += -60.0
|
||||||
|
imageSize = CGSize(width: 112.0, height: 112.0)
|
||||||
|
} else {
|
||||||
|
insets.top += -160.0
|
||||||
|
}
|
||||||
|
|
||||||
let imageSpacing: CGFloat = 12.0
|
let imageSpacing: CGFloat = 12.0
|
||||||
let textSpacing: CGFloat = 16.0
|
let textSpacing: CGFloat = 12.0
|
||||||
let buttonSpacing: CGFloat = 15.0
|
let buttonSpacing: CGFloat = 15.0
|
||||||
let cameraSpacing: CGFloat = 13.0
|
let cameraSpacing: CGFloat = 13.0
|
||||||
|
|
||||||
let imageSize = CGSize(width: 144.0, height: 144.0)
|
|
||||||
let imageHeight = layout.size.width < layout.size.height ? imageSize.height + imageSpacing : 0.0
|
let imageHeight = layout.size.width < layout.size.height ? imageSize.height + imageSpacing : 0.0
|
||||||
|
|
||||||
self.animationNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - imageSize.width) / 2.0), y: -10.0), size: imageSize)
|
|
||||||
self.animationNode.updateLayout(size: imageSize)
|
|
||||||
|
|
||||||
if themeUpdated {
|
if themeUpdated {
|
||||||
self.buttonNode.updateTheme(SolidRoundedButtonTheme(theme: theme))
|
self.buttonNode.updateTheme(SolidRoundedButtonTheme(theme: theme))
|
||||||
self.cameraIconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Attach Menu/OpenCamera"), color: theme.list.itemAccentColor)
|
self.cameraIconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Attach Menu/OpenCamera"), color: theme.list.itemAccentColor)
|
||||||
@ -116,12 +141,23 @@ final class MediaPickerPlaceholderNode: ASDisplayNode {
|
|||||||
let buttonWidth: CGFloat = 248.0
|
let buttonWidth: CGFloat = 248.0
|
||||||
let buttonHeight = self.buttonNode.updateLayout(width: buttonWidth, transition: transition)
|
let buttonHeight = self.buttonNode.updateLayout(width: buttonWidth, transition: transition)
|
||||||
|
|
||||||
self.titleNode.attributedText = NSAttributedString(string: strings.Attachment_MediaAccessTitle, font: Font.medium(17.0), textColor: theme.list.itemPrimaryTextColor, paragraphAlignment: .center)
|
let title: String
|
||||||
self.textNode.attributedText = NSAttributedString(string: strings.Attachment_MediaAccessText, font: Font.regular(15.0), textColor: theme.list.freeTextColor, paragraphAlignment: .center)
|
let text: String
|
||||||
|
switch self.content {
|
||||||
|
case .intro:
|
||||||
|
title = strings.Attachment_MediaAccessTitle
|
||||||
|
text = strings.Attachment_MediaAccessText
|
||||||
|
case let .bannedSendMedia(banDescription):
|
||||||
|
title = ""
|
||||||
|
text = banDescription
|
||||||
|
}
|
||||||
|
|
||||||
|
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.medium(17.0), textColor: theme.list.itemPrimaryTextColor, paragraphAlignment: .center)
|
||||||
|
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: theme.list.freeTextColor, paragraphAlignment: .center)
|
||||||
self.cameraTextNode.attributedText = NSAttributedString(string: strings.Attachment_OpenCamera, font: Font.regular(17.0), textColor: theme.list.itemAccentColor, paragraphAlignment: .center)
|
self.cameraTextNode.attributedText = NSAttributedString(string: strings.Attachment_OpenCamera, font: Font.regular(17.0), textColor: theme.list.itemAccentColor, paragraphAlignment: .center)
|
||||||
|
|
||||||
let titleSize = self.titleNode.updateLayout(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 70.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
let titleSize = self.titleNode.updateLayout(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 40.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
||||||
let textSize = self.textNode.updateLayout(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 70.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
let textSize = self.textNode.updateLayout(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 40.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
||||||
let cameraSize = self.cameraTextNode.updateLayout(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 70.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
let cameraSize = self.cameraTextNode.updateLayout(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 70.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
||||||
|
|
||||||
let totalHeight = imageHeight + titleSize.height + textSpacing + textSize.height + buttonSpacing + buttonHeight + cameraSpacing + cameraSize.height
|
let totalHeight = imageHeight + titleSize.height + textSpacing + textSize.height + buttonSpacing + buttonHeight + cameraSpacing + cameraSize.height
|
||||||
@ -129,6 +165,8 @@ final class MediaPickerPlaceholderNode: ASDisplayNode {
|
|||||||
|
|
||||||
transition.updateAlpha(node: self.animationNode, alpha: imageHeight > 0.0 ? 1.0 : 0.0)
|
transition.updateAlpha(node: self.animationNode, alpha: imageHeight > 0.0 ? 1.0 : 0.0)
|
||||||
transition.updateFrame(node: self.animationNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - imageSize.width) / 2.0), y: topOffset), size: imageSize))
|
transition.updateFrame(node: self.animationNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - imageSize.width) / 2.0), y: topOffset), size: imageSize))
|
||||||
|
self.animationNode.updateLayout(size: imageSize)
|
||||||
|
|
||||||
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((layout.size.width - titleSize.width - layout.safeInsets.left - layout.safeInsets.right) / 2.0), y: topOffset + imageHeight), size: titleSize))
|
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((layout.size.width - titleSize.width - layout.safeInsets.left - layout.safeInsets.right) / 2.0), y: topOffset + imageHeight), size: titleSize))
|
||||||
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((layout.size.width - textSize.width - layout.safeInsets.left - layout.safeInsets.right) / 2.0), y: self.titleNode.frame.maxY + textSpacing), size: textSize))
|
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((layout.size.width - textSize.width - layout.safeInsets.left - layout.safeInsets.right) / 2.0), y: self.titleNode.frame.maxY + textSpacing), size: textSize))
|
||||||
|
|
||||||
|
@ -75,12 +75,14 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
private var presentationDataDisposable: Disposable?
|
private var presentationDataDisposable: Disposable?
|
||||||
|
private let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
|
||||||
|
|
||||||
fileprivate var interaction: MediaPickerInteraction?
|
fileprivate var interaction: MediaPickerInteraction?
|
||||||
|
|
||||||
private let peer: EnginePeer?
|
private let peer: EnginePeer?
|
||||||
private let chatLocation: ChatLocation?
|
private let chatLocation: ChatLocation?
|
||||||
private let bannedSendMedia: (Int32, Bool)?
|
private let bannedSendMedia: (Int32, Bool)?
|
||||||
|
private let collection: PHAssetCollection?
|
||||||
|
|
||||||
private let titleView: MediaPickerTitleView
|
private let titleView: MediaPickerTitleView
|
||||||
private let moreButtonNode: MediaPickerMoreButtonNode
|
private let moreButtonNode: MediaPickerMoreButtonNode
|
||||||
@ -91,13 +93,15 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
public var presentStickers: ((@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?)?
|
public var presentStickers: ((@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?)?
|
||||||
public var presentSchedulePicker: (Bool, @escaping (Int32) -> Void) -> Void = { _, _ in }
|
public var presentSchedulePicker: (Bool, @escaping (Int32) -> Void) -> Void = { _, _ in }
|
||||||
public var presentTimerPicker: (@escaping (Int32) -> Void) -> Void = { _ in }
|
public var presentTimerPicker: (@escaping (Int32) -> Void) -> Void = { _ in }
|
||||||
public var presentWebSearch: () -> Void = {}
|
public var presentWebSearch: (MediaGroupsScreen) -> Void = { _ in }
|
||||||
public var getCaptionPanelView: () -> TGCaptionPanelView? = { return nil }
|
public var getCaptionPanelView: () -> TGCaptionPanelView? = { return nil }
|
||||||
|
|
||||||
public var legacyCompletion: (_ signals: [Any], _ silently: Bool, _ scheduleTime: Int32?) -> Void = { _, _, _ in }
|
public var legacyCompletion: (_ signals: [Any], _ silently: Bool, _ scheduleTime: Int32?) -> Void = { _, _, _ in }
|
||||||
|
|
||||||
public var requestAttachmentMenuExpansion: () -> Void = {}
|
public var requestAttachmentMenuExpansion: () -> Void = { }
|
||||||
|
public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> [AttachmentContainable]) -> Void = { _ in }
|
||||||
|
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
|
||||||
|
|
||||||
private class Node: ViewControllerTracingNode {
|
private class Node: ViewControllerTracingNode {
|
||||||
enum DisplayMode {
|
enum DisplayMode {
|
||||||
case all
|
case all
|
||||||
@ -111,14 +115,17 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
|
|
||||||
private weak var controller: MediaPickerScreen?
|
private weak var controller: MediaPickerScreen?
|
||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
private let mediaAssetsContext: MediaAssetsContext
|
fileprivate let mediaAssetsContext: MediaAssetsContext
|
||||||
|
|
||||||
|
private var requestedMediaAccess = false
|
||||||
|
private var requestedCameraAccess = false
|
||||||
|
|
||||||
|
private let containerNode: ASDisplayNode
|
||||||
private let backgroundNode: NavigationBackgroundNode
|
private let backgroundNode: NavigationBackgroundNode
|
||||||
private let gridNode: GridNode
|
private let gridNode: GridNode
|
||||||
fileprivate var cameraView: TGAttachmentCameraView?
|
fileprivate var cameraView: TGAttachmentCameraView?
|
||||||
private var placeholderNode: MediaPickerPlaceholderNode?
|
private var placeholderNode: MediaPickerPlaceholderNode?
|
||||||
private var manageNode: MediaPickerManageNode?
|
private var manageNode: MediaPickerManageNode?
|
||||||
private var bannedTextNode: ImmediateTextNode?
|
|
||||||
|
|
||||||
private var selectionNode: MediaPickerSelectedListNode?
|
private var selectionNode: MediaPickerSelectedListNode?
|
||||||
|
|
||||||
@ -137,7 +144,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
private let hiddenMediaId = Promise<String?>(nil)
|
private let hiddenMediaId = Promise<String?>(nil)
|
||||||
|
|
||||||
private var didSetReady = false
|
private var didSetReady = false
|
||||||
private let _ready = Promise<Bool>(true)
|
private let _ready = Promise<Bool>()
|
||||||
var ready: Promise<Bool> {
|
var ready: Promise<Bool> {
|
||||||
return self._ready
|
return self._ready
|
||||||
}
|
}
|
||||||
@ -151,16 +158,20 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
let mediaAssetsContext = MediaAssetsContext()
|
let mediaAssetsContext = MediaAssetsContext()
|
||||||
self.mediaAssetsContext = mediaAssetsContext
|
self.mediaAssetsContext = mediaAssetsContext
|
||||||
|
|
||||||
|
self.containerNode = ASDisplayNode()
|
||||||
self.backgroundNode = NavigationBackgroundNode(color: self.presentationData.theme.rootController.tabBar.backgroundColor)
|
self.backgroundNode = NavigationBackgroundNode(color: self.presentationData.theme.rootController.tabBar.backgroundColor)
|
||||||
|
self.backgroundNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||||
self.gridNode = GridNode()
|
self.gridNode = GridNode()
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
// self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||||
|
|
||||||
self.addSubnode(self.backgroundNode)
|
self.addSubnode(self.containerNode)
|
||||||
self.addSubnode(self.gridNode)
|
self.containerNode.addSubnode(self.backgroundNode)
|
||||||
|
self.containerNode.addSubnode(self.gridNode)
|
||||||
|
|
||||||
|
let collection = controller.collection
|
||||||
let preloadPromise = self.preloadPromise
|
let preloadPromise = self.preloadPromise
|
||||||
let updatedState = combineLatest(mediaAssetsContext.mediaAccess(), mediaAssetsContext.cameraAccess())
|
let updatedState = combineLatest(mediaAssetsContext.mediaAccess(), mediaAssetsContext.cameraAccess())
|
||||||
|> mapToSignal { mediaAccess, cameraAccess -> Signal<State, NoError> in
|
|> mapToSignal { mediaAccess, cameraAccess -> Signal<State, NoError> in
|
||||||
@ -169,9 +180,16 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
} else if [.restricted, .denied].contains(mediaAccess) {
|
} else if [.restricted, .denied].contains(mediaAccess) {
|
||||||
return .single(.noAccess(cameraAccess: cameraAccess))
|
return .single(.noAccess(cameraAccess: cameraAccess))
|
||||||
} else {
|
} else {
|
||||||
return combineLatest(mediaAssetsContext.recentAssets(), preloadPromise.get())
|
if let collection = collection {
|
||||||
|> map { fetchResult, preload in
|
return combineLatest(mediaAssetsContext.fetchAssets(collection), preloadPromise.get())
|
||||||
return .assets(fetchResult: fetchResult, preload: preload, mediaAccess: mediaAccess, cameraAccess: cameraAccess)
|
|> map { fetchResult, preload in
|
||||||
|
return .assets(fetchResult: fetchResult, preload: preload, mediaAccess: mediaAccess, cameraAccess: cameraAccess)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return combineLatest(mediaAssetsContext.recentAssets(), preloadPromise.get())
|
||||||
|
|> map { fetchResult, preload in
|
||||||
|
return .assets(fetchResult: fetchResult, preload: preload, mediaAccess: mediaAccess, cameraAccess: cameraAccess)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,6 +206,10 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
self?.dismissInput()
|
self?.dismissInput()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.gridNode.visibleContentOffsetChanged = { [weak self] _ in
|
||||||
|
self?.updateNavigation(transition: .immediate)
|
||||||
|
}
|
||||||
|
|
||||||
self.hiddenMediaDisposable = (self.hiddenMediaId.get()
|
self.hiddenMediaDisposable = (self.hiddenMediaId.get()
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] id in
|
|> deliverOnMainQueue).start(next: { [weak self] id in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
@ -257,18 +279,22 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
self.gridNode.scrollView.alwaysBounceVertical = true
|
self.gridNode.scrollView.alwaysBounceVertical = true
|
||||||
self.gridNode.scrollView.showsVerticalScrollIndicator = false
|
self.gridNode.scrollView.showsVerticalScrollIndicator = false
|
||||||
|
|
||||||
let cameraView = TGAttachmentCameraView(forSelfPortrait: false)!
|
if self.controller?.collection == nil {
|
||||||
cameraView.clipsToBounds = true
|
let cameraView = TGAttachmentCameraView(forSelfPortrait: false)!
|
||||||
cameraView.removeCorners()
|
cameraView.clipsToBounds = true
|
||||||
cameraView.pressed = { [weak self] in
|
cameraView.removeCorners()
|
||||||
if let strongSelf = self {
|
cameraView.pressed = { [weak self] in
|
||||||
strongSelf.controller?.openCamera?(strongSelf.cameraView)
|
if let strongSelf = self, !strongSelf.openingMedia {
|
||||||
|
strongSelf.controller?.openCamera?(strongSelf.cameraView)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
self.cameraView = cameraView
|
||||||
|
cameraView.startPreview()
|
||||||
|
|
||||||
|
self.gridNode.scrollView.addSubview(cameraView)
|
||||||
|
} else {
|
||||||
|
self.containerNode.clipsToBounds = true
|
||||||
}
|
}
|
||||||
self.cameraView = cameraView
|
|
||||||
cameraView.startPreview()
|
|
||||||
|
|
||||||
self.gridNode.scrollView.addSubview(cameraView)
|
|
||||||
|
|
||||||
// self.controller?.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate)
|
// self.controller?.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate)
|
||||||
}
|
}
|
||||||
@ -277,9 +303,6 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
self.view.window?.endEditing(true)
|
self.view.window?.endEditing(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var requestedMediaAccess = false
|
|
||||||
private var requestedCameraAccess = false
|
|
||||||
|
|
||||||
private func updateState(_ state: State) {
|
private func updateState(_ state: State) {
|
||||||
guard let controller = self.controller, let interaction = controller.interaction else {
|
guard let controller = self.controller, let interaction = controller.interaction else {
|
||||||
return
|
return
|
||||||
@ -337,6 +360,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
if updateLayout, let (layout, navigationBarHeight) = self.validLayout {
|
if updateLayout, let (layout, navigationBarHeight) = self.validLayout {
|
||||||
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: previousState == nil ? .immediate : .animated(duration: 0.2, curve: .easeInOut))
|
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: previousState == nil ? .immediate : .animated(duration: 0.2, curve: .easeInOut))
|
||||||
}
|
}
|
||||||
|
self.updateNavigation(transition: .immediate)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateSelectionState() {
|
private func updateSelectionState() {
|
||||||
@ -358,19 +382,22 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
func updatePresentationData(_ presentationData: PresentationData) {
|
func updatePresentationData(_ presentationData: PresentationData) {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
|
|
||||||
self.backgroundColor = presentationData.theme.list.plainBackgroundColor
|
self.backgroundNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||||
|
self.backgroundNode.updateColor(color: self.presentationData.theme.rootController.tabBar.backgroundColor, transition: .immediate)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var currentDisplayMode: DisplayMode = .all
|
private var currentDisplayMode: DisplayMode = .all
|
||||||
func updateMode(_ displayMode: DisplayMode) {
|
func updateMode(_ displayMode: DisplayMode) {
|
||||||
|
let updated = self.currentDisplayMode != displayMode
|
||||||
self.currentDisplayMode = displayMode
|
self.currentDisplayMode = displayMode
|
||||||
|
|
||||||
if case .selected = displayMode, self.selectionNode == nil, let controller = self.controller {
|
if case .selected = displayMode, self.selectionNode == nil, let controller = self.controller {
|
||||||
let selectionNode = MediaPickerSelectedListNode(context: controller.context)
|
let selectionNode = MediaPickerSelectedListNode(context: controller.context)
|
||||||
|
selectionNode.layer.allowsGroupOpacity = true
|
||||||
selectionNode.alpha = 0.0
|
selectionNode.alpha = 0.0
|
||||||
selectionNode.isUserInteractionEnabled = false
|
selectionNode.isUserInteractionEnabled = false
|
||||||
selectionNode.interaction = self.controller?.interaction
|
selectionNode.interaction = self.controller?.interaction
|
||||||
self.insertSubnode(selectionNode, aboveSubnode: self.gridNode)
|
self.containerNode.insertSubnode(selectionNode, aboveSubnode: self.gridNode)
|
||||||
self.selectionNode = selectionNode
|
self.selectionNode = selectionNode
|
||||||
|
|
||||||
if let (layout, navigationBarHeight) = self.validLayout {
|
if let (layout, navigationBarHeight) = self.validLayout {
|
||||||
@ -381,22 +408,42 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
|
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
|
||||||
self.gridNode.isUserInteractionEnabled = displayMode == .all
|
self.gridNode.isUserInteractionEnabled = displayMode == .all
|
||||||
|
|
||||||
|
var completion: () -> Void = {}
|
||||||
|
if updated && displayMode == .all {
|
||||||
|
completion = {
|
||||||
|
self.updateNavigation(transition: .animated(duration: 0.1, curve: .easeInOut))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let selectionNode = self.selectionNode {
|
if let selectionNode = self.selectionNode {
|
||||||
transition.updateAlpha(node: selectionNode, alpha: displayMode == .selected ? 1.0 : 0.0)
|
transition.updateAlpha(node: selectionNode, alpha: displayMode == .selected ? 1.0 : 0.0, completion: { _ in
|
||||||
|
completion()
|
||||||
|
})
|
||||||
selectionNode.isUserInteractionEnabled = displayMode == .selected
|
selectionNode.isUserInteractionEnabled = displayMode == .selected
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if updated && displayMode == .selected {
|
||||||
|
self.updateNavigation(transition: .immediate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var openingMedia = false
|
||||||
fileprivate func openMedia(fetchResult: PHFetchResult<PHAsset>, index: Int, immediateThumbnail: UIImage?) {
|
fileprivate func openMedia(fetchResult: PHFetchResult<PHAsset>, index: Int, immediateThumbnail: UIImage?) {
|
||||||
guard let controller = self.controller, let interaction = controller.interaction, let (layout, _) = self.validLayout else {
|
guard let controller = self.controller, let interaction = controller.interaction, let (layout, _) = self.validLayout, !self.openingMedia else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Queue.mainQueue().justDispatch {
|
Queue.mainQueue().justDispatch {
|
||||||
self.dismissInput()
|
self.dismissInput()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var hasTimer = false
|
||||||
|
if controller.chatLocation?.peerId != controller.context.account.peerId && controller.chatLocation?.peerId.namespace == Namespaces.Peer.CloudUser {
|
||||||
|
hasTimer = true
|
||||||
|
}
|
||||||
|
|
||||||
|
self.openingMedia = true
|
||||||
let index = fetchResult.count - index - 1
|
let index = fetchResult.count - index - 1
|
||||||
presentLegacyMediaPickerGallery(context: controller.context, peer: controller.peer, chatLocation: controller.chatLocation, presentationData: self.presentationData, source: .fetchResult(fetchResult: fetchResult, index: index), immediateThumbnail: immediateThumbnail, selectionContext: interaction.selectionState, editingContext: interaction.editingState, hasSilentPosting: true, hasSchedule: true, hasTimer: true, updateHiddenMedia: { [weak self] id in
|
presentLegacyMediaPickerGallery(context: controller.context, peer: controller.peer, chatLocation: controller.chatLocation, presentationData: self.presentationData, source: .fetchResult(fetchResult: fetchResult, index: index), immediateThumbnail: immediateThumbnail, selectionContext: interaction.selectionState, editingContext: interaction.editingState, hasSilentPosting: true, hasSchedule: true, hasTimer: hasTimer, updateHiddenMedia: { [weak self] id in
|
||||||
self?.hiddenMediaId.set(.single(id))
|
self?.hiddenMediaId.set(.single(id))
|
||||||
}, initialLayout: layout, transitionHostView: { [weak self] in
|
}, initialLayout: layout, transitionHostView: { [weak self] in
|
||||||
return self?.gridNode.view
|
return self?.gridNode.view
|
||||||
@ -408,18 +455,26 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
}
|
}
|
||||||
}, presentStickers: controller.presentStickers, presentSchedulePicker: controller.presentSchedulePicker, presentTimerPicker: controller.presentTimerPicker, getCaptionPanelView: controller.getCaptionPanelView, present: { [weak self] c, a in
|
}, presentStickers: controller.presentStickers, presentSchedulePicker: controller.presentSchedulePicker, presentTimerPicker: controller.presentTimerPicker, getCaptionPanelView: controller.getCaptionPanelView, present: { [weak self] c, a in
|
||||||
self?.controller?.present(c, in: .window(.root), with: a)
|
self?.controller?.present(c, in: .window(.root), with: a)
|
||||||
|
}, finishedTransitionIn: {
|
||||||
|
self.openingMedia = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func openSelectedMedia(item: TGMediaSelectableItem, immediateThumbnail: UIImage?) {
|
fileprivate func openSelectedMedia(item: TGMediaSelectableItem, immediateThumbnail: UIImage?) {
|
||||||
guard let controller = self.controller, let interaction = controller.interaction, let (layout, _) = self.validLayout else {
|
guard let controller = self.controller, let interaction = controller.interaction, let (layout, _) = self.validLayout, !self.openingMedia else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Queue.mainQueue().justDispatch {
|
Queue.mainQueue().justDispatch {
|
||||||
self.dismissInput()
|
self.dismissInput()
|
||||||
}
|
}
|
||||||
|
|
||||||
presentLegacyMediaPickerGallery(context: controller.context, peer: controller.peer, chatLocation: controller.chatLocation, presentationData: self.presentationData, source: .selection(item: item), immediateThumbnail: immediateThumbnail, selectionContext: interaction.selectionState, editingContext: interaction.editingState, hasSilentPosting: true, hasSchedule: true, hasTimer: true, updateHiddenMedia: { [weak self] id in
|
var hasTimer = false
|
||||||
|
if controller.chatLocation?.peerId != controller.context.account.peerId && controller.chatLocation?.peerId.namespace == Namespaces.Peer.CloudUser {
|
||||||
|
hasTimer = true
|
||||||
|
}
|
||||||
|
|
||||||
|
self.openingMedia = true
|
||||||
|
presentLegacyMediaPickerGallery(context: controller.context, peer: controller.peer, chatLocation: controller.chatLocation, presentationData: self.presentationData, source: .selection(item: item), immediateThumbnail: immediateThumbnail, selectionContext: interaction.selectionState, editingContext: interaction.editingState, hasSilentPosting: true, hasSchedule: true, hasTimer: hasTimer, updateHiddenMedia: { [weak self] id in
|
||||||
self?.hiddenMediaId.set(.single(id))
|
self?.hiddenMediaId.set(.single(id))
|
||||||
}, initialLayout: layout, transitionHostView: { [weak self] in
|
}, initialLayout: layout, transitionHostView: { [weak self] in
|
||||||
return self?.selectionNode?.view
|
return self?.selectionNode?.view
|
||||||
@ -430,16 +485,40 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
strongSelf.controller?.interaction?.sendSelected(result, silently, scheduleTime, false)
|
strongSelf.controller?.interaction?.sendSelected(result, silently, scheduleTime, false)
|
||||||
}
|
}
|
||||||
}, presentStickers: controller.presentStickers, presentSchedulePicker: controller.presentSchedulePicker, presentTimerPicker: controller.presentTimerPicker, getCaptionPanelView: controller.getCaptionPanelView, present: { [weak self] c, a in
|
}, presentStickers: controller.presentStickers, presentSchedulePicker: controller.presentSchedulePicker, presentTimerPicker: controller.presentTimerPicker, getCaptionPanelView: controller.getCaptionPanelView, present: { [weak self] c, a in
|
||||||
self?.controller?.present(c, in: .window(.root), with: a)
|
self?.controller?.present(c, in: .window(.root), with: a, blockInteraction: true)
|
||||||
|
}, finishedTransitionIn: {
|
||||||
|
self.openingMedia = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func send(asFile: Bool = false, silently: Bool, scheduleTime: Int32?, animated: Bool) {
|
fileprivate func send(asFile: Bool = false, silently: Bool, scheduleTime: Int32?, animated: Bool) {
|
||||||
guard let signals = TGMediaAssetsController.resultSignals(for: self.controller?.interaction?.selectionState, editingContext: self.controller?.interaction?.editingState, intent: asFile ? TGMediaAssetsControllerSendFileIntent : TGMediaAssetsControllerSendMediaIntent, currentItem: nil, storeAssets: true, convertToJpeg: false, descriptionGenerator: legacyAssetPickerItemGenerator(), saveEditedPhotos: true) else {
|
var hasHeic = false
|
||||||
return
|
let allItems = self.controller?.interaction?.selectionState?.selectedItems() ?? []
|
||||||
|
for item in allItems {
|
||||||
|
if item is TGCameraCapturedVideo {
|
||||||
|
} else if let asset = item as? TGMediaAsset, asset.uniformTypeIdentifier.contains("heic") {
|
||||||
|
hasHeic = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let proceed: (Bool) -> Void = { convertToJpeg in
|
||||||
|
guard let signals = TGMediaAssetsController.resultSignals(for: self.controller?.interaction?.selectionState, editingContext: self.controller?.interaction?.editingState, intent: asFile ? TGMediaAssetsControllerSendFileIntent : TGMediaAssetsControllerSendMediaIntent, currentItem: nil, storeAssets: true, convertToJpeg: false, descriptionGenerator: legacyAssetPickerItemGenerator(), saveEditedPhotos: true) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.controller?.legacyCompletion(signals, silently, scheduleTime)
|
||||||
|
self.controller?.dismiss(animated: animated)
|
||||||
|
}
|
||||||
|
|
||||||
|
if asFile && hasHeic {
|
||||||
|
self.controller?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: self.presentationData.strings.MediaPicker_JpegConversionText, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.MediaPicker_KeepHeic, action: {
|
||||||
|
proceed(false)
|
||||||
|
}), TextAlertAction(type: .genericAction, title: self.presentationData.strings.MediaPicker_ConvertToJpeg, action: {
|
||||||
|
proceed(true)
|
||||||
|
})], actionLayout: .vertical), in: .window(.root))
|
||||||
|
} else {
|
||||||
|
proceed(false)
|
||||||
}
|
}
|
||||||
self.controller?.legacyCompletion(signals, silently, scheduleTime)
|
|
||||||
self.controller?.dismiss(animated: animated)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func openLimitedMediaOptions() {
|
private func openLimitedMediaOptions() {
|
||||||
@ -504,6 +583,42 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var previousContentOffset: GridNodeVisibleContentOffset?
|
||||||
|
|
||||||
|
func updateNavigation(transition: ContainedViewLayoutTransition) {
|
||||||
|
if let selectionNode = self.selectionNode, selectionNode.alpha > 0.0 {
|
||||||
|
self.controller?.navigationBar?.updateBackgroundAlpha(1.0, transition: .immediate)
|
||||||
|
self.controller?.updateTabBarAlpha(1.0, transition)
|
||||||
|
} else if self.placeholderNode != nil {
|
||||||
|
self.controller?.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate)
|
||||||
|
self.controller?.updateTabBarAlpha(0.0, transition)
|
||||||
|
} else {
|
||||||
|
var previousContentOffsetValue: CGFloat?
|
||||||
|
if let previousContentOffset = self.previousContentOffset, case let .known(value) = previousContentOffset {
|
||||||
|
previousContentOffsetValue = value
|
||||||
|
}
|
||||||
|
|
||||||
|
let offset = self.gridNode.visibleContentOffset()
|
||||||
|
switch offset {
|
||||||
|
case let .known(value):
|
||||||
|
let transition: ContainedViewLayoutTransition
|
||||||
|
if let previousContentOffsetValue = previousContentOffsetValue, value <= 0.0, previousContentOffsetValue > 2.0 {
|
||||||
|
transition = .animated(duration: 0.2, curve: .easeInOut)
|
||||||
|
} else {
|
||||||
|
transition = .immediate
|
||||||
|
}
|
||||||
|
self.controller?.navigationBar?.updateBackgroundAlpha(min(2.0, value) / 2.0, transition: transition)
|
||||||
|
case .unknown, .none:
|
||||||
|
self.controller?.navigationBar?.updateBackgroundAlpha(1.0, transition: .immediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let count = Int32(self.controller?.interaction?.selectionState?.count() ?? 0)
|
||||||
|
if count > 0 {
|
||||||
|
self.controller?.updateTabBarAlpha(1.0, transition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
let firstTime = self.validLayout == nil
|
let firstTime = self.validLayout == nil
|
||||||
self.validLayout = (layout, navigationBarHeight)
|
self.validLayout = (layout, navigationBarHeight)
|
||||||
@ -511,10 +626,13 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
var insets = layout.insets(options: [])
|
var insets = layout.insets(options: [])
|
||||||
insets.top += navigationBarHeight
|
insets.top += navigationBarHeight
|
||||||
|
|
||||||
|
let overflowInset: CGFloat = 70.0
|
||||||
let bounds = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: layout.size.height))
|
let bounds = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: layout.size.height))
|
||||||
|
let innerBounds = CGRect(origin: CGPoint(x: -overflowInset, y: 0.0), size: CGSize(width: layout.size.width, height: layout.size.height))
|
||||||
|
|
||||||
let itemsPerRow: Int
|
let itemsPerRow: Int
|
||||||
if case .compact = layout.metrics.widthClass {
|
if case .compact = layout.metrics.widthClass {
|
||||||
|
self._ready.set(.single(true))
|
||||||
switch layout.orientation {
|
switch layout.orientation {
|
||||||
case .portrait:
|
case .portrait:
|
||||||
itemsPerRow = 3
|
itemsPerRow = 3
|
||||||
@ -529,6 +647,9 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
let itemWidth = floorToScreenPixels((width - itemSpacing * CGFloat(itemsPerRow - 1)) / CGFloat(itemsPerRow))
|
let itemWidth = floorToScreenPixels((width - itemSpacing * CGFloat(itemsPerRow - 1)) / CGFloat(itemsPerRow))
|
||||||
|
|
||||||
var cameraRect: CGRect? = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: 0.0), size: CGSize(width: itemWidth, height: itemWidth * 2.0 + 1.0))
|
var cameraRect: CGRect? = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: 0.0), size: CGSize(width: itemWidth, height: itemWidth * 2.0 + 1.0))
|
||||||
|
if self.cameraView == nil {
|
||||||
|
cameraRect = nil
|
||||||
|
}
|
||||||
|
|
||||||
var manageHeight: CGFloat = 0.0
|
var manageHeight: CGFloat = 0.0
|
||||||
if case let .assets(_, _, mediaAccess, cameraAccess) = self.state {
|
if case let .assets(_, _, mediaAccess, cameraAccess) = self.state {
|
||||||
@ -536,8 +657,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
cameraRect = nil
|
cameraRect = nil
|
||||||
}
|
}
|
||||||
if let (untilDate, personal) = self.controller?.bannedSendMedia {
|
if let (untilDate, personal) = self.controller?.bannedSendMedia {
|
||||||
self.gridNode.alpha = 0.3
|
self.gridNode.isHidden = true
|
||||||
self.gridNode.isUserInteractionEnabled = false
|
|
||||||
|
|
||||||
let banDescription: String
|
let banDescription: String
|
||||||
if untilDate != 0 && untilDate != Int32.max {
|
if untilDate != 0 && untilDate != Int32.max {
|
||||||
@ -548,24 +668,21 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
banDescription = self.presentationData.strings.Conversation_DefaultRestrictedMedia
|
banDescription = self.presentationData.strings.Conversation_DefaultRestrictedMedia
|
||||||
}
|
}
|
||||||
|
|
||||||
let bannedTextNode: ImmediateTextNode
|
var placeholderTransition = transition
|
||||||
if let current = self.bannedTextNode {
|
let placeholderNode: MediaPickerPlaceholderNode
|
||||||
bannedTextNode = current
|
if let current = self.placeholderNode {
|
||||||
|
placeholderNode = current
|
||||||
} else {
|
} else {
|
||||||
bannedTextNode = ImmediateTextNode()
|
placeholderNode = MediaPickerPlaceholderNode(content: .bannedSendMedia(banDescription))
|
||||||
bannedTextNode.maximumNumberOfLines = 0
|
self.containerNode.insertSubnode(placeholderNode, aboveSubnode: self.gridNode)
|
||||||
bannedTextNode.textAlignment = .center
|
self.placeholderNode = placeholderNode
|
||||||
self.bannedTextNode = bannedTextNode
|
|
||||||
self.addSubnode(bannedTextNode)
|
placeholderTransition = .immediate
|
||||||
}
|
}
|
||||||
|
placeholderNode.update(layout: layout, theme: self.presentationData.theme, strings: self.presentationData.strings, hasCamera: false, transition: placeholderTransition)
|
||||||
|
placeholderTransition.updateFrame(node: placeholderNode, frame: innerBounds)
|
||||||
|
|
||||||
bannedTextNode.attributedText = NSAttributedString(string: banDescription, font: Font.regular(15.0), textColor: self.presentationData.theme.list.freeTextColor, paragraphAlignment: .center)
|
self.updateNavigation(transition: .immediate)
|
||||||
|
|
||||||
let bannedTextSize = bannedTextNode.updateLayout(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 16.0, height: layout.size.height))
|
|
||||||
|
|
||||||
manageHeight = max(44.0, bannedTextSize.height + 20.0)
|
|
||||||
|
|
||||||
transition.updateFrame(node: bannedTextNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - bannedTextSize.width) / 2.0), y: insets.top + floorToScreenPixels((manageHeight - bannedTextSize.height) / 2.0) - 4.0), size: bannedTextSize))
|
|
||||||
} else if case .notDetermined = mediaAccess {
|
} else if case .notDetermined = mediaAccess {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -612,11 +729,13 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
|
|
||||||
let cleanGridInsets = UIEdgeInsets(top: insets.top, left: layout.safeInsets.left, bottom: layout.intrinsicInsets.bottom, right: layout.safeInsets.right)
|
let cleanGridInsets = UIEdgeInsets(top: insets.top, left: layout.safeInsets.left, bottom: layout.intrinsicInsets.bottom, right: layout.safeInsets.right)
|
||||||
let gridInsets = UIEdgeInsets(top: insets.top + manageHeight, left: layout.safeInsets.left, bottom: layout.intrinsicInsets.bottom, right: layout.safeInsets.right)
|
let gridInsets = UIEdgeInsets(top: insets.top + manageHeight, left: layout.safeInsets.left, bottom: layout.intrinsicInsets.bottom, right: layout.safeInsets.right)
|
||||||
transition.updateFrame(node: self.gridNode, frame: bounds)
|
transition.updateFrame(node: self.gridNode, frame: innerBounds)
|
||||||
|
|
||||||
transition.updateFrame(node: self.backgroundNode, frame: bounds)
|
transition.updateFrame(node: self.backgroundNode, frame: innerBounds)
|
||||||
self.backgroundNode.update(size: bounds.size, transition: transition)
|
self.backgroundNode.update(size: bounds.size, transition: transition)
|
||||||
|
|
||||||
|
transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(x: overflowInset, y: 0.0), size: CGSize(width: bounds.width - overflowInset * 2.0, height: bounds.height)))
|
||||||
|
|
||||||
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: bounds.size, insets: gridInsets, scrollIndicatorInsets: nil, preloadSize: itemWidth, type: .fixed(itemSize: CGSize(width: itemWidth, height: itemWidth), fillWidth: true, lineSpacing: itemSpacing, itemSpacing: itemSpacing), cutout: cameraRect), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil, updateOpaqueState: nil, synchronousLoads: false), completion: { [weak self] _ in
|
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: bounds.size, insets: gridInsets, scrollIndicatorInsets: nil, preloadSize: itemWidth, type: .fixed(itemSize: CGSize(width: itemWidth, height: itemWidth), fillWidth: true, lineSpacing: itemSpacing, itemSpacing: itemSpacing), cutout: cameraRect), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil, updateOpaqueState: nil, synchronousLoads: false), completion: { [weak self] _ in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -645,7 +764,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
} else {
|
} else {
|
||||||
updateSelectionNode()
|
updateSelectionNode()
|
||||||
}
|
}
|
||||||
transition.updateFrame(node: selectionNode, frame: bounds)
|
transition.updateFrame(node: selectionNode, frame: innerBounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let cameraView = self.cameraView {
|
if let cameraView = self.cameraView {
|
||||||
@ -669,24 +788,26 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
if let current = self.placeholderNode {
|
if let current = self.placeholderNode {
|
||||||
placeholderNode = current
|
placeholderNode = current
|
||||||
} else {
|
} else {
|
||||||
placeholderNode = MediaPickerPlaceholderNode()
|
placeholderNode = MediaPickerPlaceholderNode(content: .intro)
|
||||||
placeholderNode.settingsPressed = { [weak self] in
|
placeholderNode.settingsPressed = { [weak self] in
|
||||||
self?.controller?.context.sharedContext.applicationBindings.openSettings()
|
self?.controller?.context.sharedContext.applicationBindings.openSettings()
|
||||||
}
|
}
|
||||||
placeholderNode.cameraPressed = { [weak self] in
|
placeholderNode.cameraPressed = { [weak self] in
|
||||||
self?.controller?.openCamera?(nil)
|
self?.controller?.openCamera?(nil)
|
||||||
}
|
}
|
||||||
self.insertSubnode(placeholderNode, aboveSubnode: self.gridNode)
|
self.containerNode.insertSubnode(placeholderNode, aboveSubnode: self.gridNode)
|
||||||
self.placeholderNode = placeholderNode
|
self.placeholderNode = placeholderNode
|
||||||
|
|
||||||
if transition.isAnimated {
|
if transition.isAnimated {
|
||||||
placeholderNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
placeholderNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||||
}
|
}
|
||||||
placeholderTransition = .immediate
|
placeholderTransition = .immediate
|
||||||
|
|
||||||
|
self.updateNavigation(transition: .immediate)
|
||||||
}
|
}
|
||||||
placeholderNode.update(layout: layout, theme: self.presentationData.theme, strings: self.presentationData.strings, hasCamera: cameraAccess == .authorized, transition: placeholderTransition)
|
placeholderNode.update(layout: layout, theme: self.presentationData.theme, strings: self.presentationData.strings, hasCamera: cameraAccess == .authorized, transition: placeholderTransition)
|
||||||
placeholderTransition.updateFrame(node: placeholderNode, frame: bounds)
|
placeholderTransition.updateFrame(node: placeholderNode, frame: innerBounds)
|
||||||
} else if let placeholderNode = self.placeholderNode {
|
} else if let placeholderNode = self.placeholderNode, self.controller?.bannedSendMedia == nil {
|
||||||
self.placeholderNode = nil
|
self.placeholderNode = nil
|
||||||
placeholderNode.removeFromSupernode()
|
placeholderNode.removeFromSupernode()
|
||||||
}
|
}
|
||||||
@ -716,19 +837,23 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
}
|
}
|
||||||
private let groupedPromise = ValuePromise<Bool>(true)
|
private let groupedPromise = ValuePromise<Bool>(true)
|
||||||
|
|
||||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: EnginePeer?, chatLocation: ChatLocation?, bannedSendMedia: (Int32, Bool)?) {
|
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: EnginePeer?, chatLocation: ChatLocation?, bannedSendMedia: (Int32, Bool)?, collection: PHAssetCollection? = nil, editingContext: TGMediaEditingContext? = nil, selectionContext: TGMediaSelectionContext? = nil) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
|
|
||||||
|
let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
self.presentationData = presentationData
|
||||||
|
self.updatedPresentationData = updatedPresentationData
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
self.chatLocation = chatLocation
|
self.chatLocation = chatLocation
|
||||||
self.bannedSendMedia = bannedSendMedia
|
self.bannedSendMedia = bannedSendMedia
|
||||||
|
self.collection = collection
|
||||||
|
|
||||||
self.titleView = MediaPickerTitleView(theme: self.presentationData.theme, segments: [self.presentationData.strings.Attachment_AllMedia, self.presentationData.strings.Attachment_SelectedMedia(1)], selectedIndex: 0)
|
self.titleView = MediaPickerTitleView(theme: self.presentationData.theme, segments: [self.presentationData.strings.Attachment_AllMedia, self.presentationData.strings.Attachment_SelectedMedia(1)], selectedIndex: 0)
|
||||||
self.titleView.title = self.presentationData.strings.Attachment_Gallery
|
self.titleView.title = collection?.localizedTitle ?? presentationData.strings.Attachment_Gallery
|
||||||
|
|
||||||
self.moreButtonNode = MediaPickerMoreButtonNode(theme: self.presentationData.theme)
|
self.moreButtonNode = MediaPickerMoreButtonNode(theme: self.presentationData.theme)
|
||||||
|
|
||||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: presentationData, hideBackground: false, hideBadge: false, hideSeparator: true))
|
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: presentationData))
|
||||||
|
|
||||||
self.statusBar.statusBarStyle = .Ignore
|
self.statusBar.statusBarStyle = .Ignore
|
||||||
|
|
||||||
@ -753,8 +878,15 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.navigationItem.titleView = self.titleView
|
self.navigationItem.titleView = self.titleView
|
||||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
|
|
||||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customDisplayNode: self.moreButtonNode)
|
if collection == nil {
|
||||||
|
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
|
||||||
|
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customDisplayNode: self.moreButtonNode)
|
||||||
|
self.navigationItem.rightBarButtonItem?.action = #selector(self.rightButtonPressed)
|
||||||
|
self.navigationItem.rightBarButtonItem?.target = self
|
||||||
|
} else {
|
||||||
|
self.navigationItem.leftBarButtonItem = UIBarButtonItem(backButtonAppearanceWithTitle: self.presentationData.strings.Common_Back, target: self, action: #selector(self.backPressed))
|
||||||
|
}
|
||||||
|
|
||||||
self.moreButtonNode.action = { [weak self] _, gesture in
|
self.moreButtonNode.action = { [weak self] _, gesture in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
@ -807,7 +939,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.controllerNode.dismissInput()
|
strongSelf.controllerNode.dismissInput()
|
||||||
}
|
}
|
||||||
}, selectionState: TGMediaSelectionContext(), editingState: TGMediaEditingContext())
|
}, selectionState: selectionContext ?? TGMediaSelectionContext(), editingState: editingContext ?? TGMediaEditingContext())
|
||||||
self.interaction?.selectionState?.grouping = true
|
self.interaction?.selectionState?.grouping = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -853,10 +985,20 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
self.controllerNode.updatePresentationData(self.presentationData)
|
self.controllerNode.updatePresentationData(self.presentationData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func backPressed() {
|
||||||
|
self.updateNavigationStack { current in
|
||||||
|
return current.filter { $0 !== self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@objc private func cancelPressed() {
|
@objc private func cancelPressed() {
|
||||||
self.dismiss()
|
self.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func rightButtonPressed() {
|
||||||
|
self.moreButtonNode.action?(self.moreButtonNode.contextSourceNode, nil)
|
||||||
|
}
|
||||||
|
|
||||||
public func resetForReuse() {
|
public func resetForReuse() {
|
||||||
if let webSearchController = self.webSearchController {
|
if let webSearchController = self.webSearchController {
|
||||||
self.webSearchController = nil
|
self.webSearchController = nil
|
||||||
@ -869,13 +1011,36 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
|
|
||||||
public func prepareForReuse() {
|
public func prepareForReuse() {
|
||||||
self.controllerNode.cameraView?.resumePreview()
|
self.controllerNode.cameraView?.resumePreview()
|
||||||
|
|
||||||
|
Queue.mainQueue().after(0.2, {
|
||||||
|
self.controllerNode.updateNavigation(transition: .animated(duration: 0.15, curve: .easeInOut))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func searchOrMorePressed(node: ContextReferenceContentNode, gesture: ContextGesture?) {
|
@objc private func searchOrMorePressed(node: ContextReferenceContentNode, gesture: ContextGesture?) {
|
||||||
switch self.moreButtonNode.iconNode.iconState {
|
switch self.moreButtonNode.iconNode.iconState {
|
||||||
case .search:
|
case .search:
|
||||||
self.requestAttachmentMenuExpansion()
|
self.requestAttachmentMenuExpansion()
|
||||||
self.presentWebSearch()
|
self.presentWebSearch(MediaGroupsScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, mediaAssetsContext: self.controllerNode.mediaAssetsContext, openGroup: { [weak self] collection in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if let webSearchController = strongSelf.webSearchController {
|
||||||
|
strongSelf.webSearchController = nil
|
||||||
|
if collection.assetCollectionSubtype != .smartAlbumUserLibrary {
|
||||||
|
Queue.mainQueue().after(0.5) {
|
||||||
|
webSearchController.cancel()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
webSearchController.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if collection.assetCollectionSubtype != .smartAlbumUserLibrary {
|
||||||
|
let mediaPicker = MediaPickerScreen(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: strongSelf.peer, chatLocation: strongSelf.chatLocation, bannedSendMedia: strongSelf.bannedSendMedia, collection: collection, editingContext: strongSelf.interaction?.editingState, selectionContext: strongSelf.interaction?.selectionState)
|
||||||
|
mediaPicker._presentedInModal = true
|
||||||
|
mediaPicker.updateNavigationStack = strongSelf.updateNavigationStack
|
||||||
|
strongSelf.updateNavigationStack({ _ in return [strongSelf, mediaPicker]})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
case .more:
|
case .more:
|
||||||
let strings = self.presentationData.strings
|
let strings = self.presentationData.strings
|
||||||
let selectionCount = self.selectionCount
|
let selectionCount = self.selectionCount
|
||||||
|
@ -652,7 +652,6 @@ private class ReorderingGestureRecognizer: UIGestureRecognizer {
|
|||||||
private let moved: (CGPoint) -> Void
|
private let moved: (CGPoint) -> Void
|
||||||
|
|
||||||
private var initialLocation: CGPoint?
|
private var initialLocation: CGPoint?
|
||||||
private var longTapTimer: SwiftSignalKit.Timer?
|
|
||||||
private var longPressTimer: SwiftSignalKit.Timer?
|
private var longPressTimer: SwiftSignalKit.Timer?
|
||||||
|
|
||||||
private var itemNode: MediaPickerSelectedItemNode?
|
private var itemNode: MediaPickerSelectedItemNode?
|
||||||
@ -668,28 +667,12 @@ private class ReorderingGestureRecognizer: UIGestureRecognizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
self.longTapTimer?.invalidate()
|
|
||||||
self.longPressTimer?.invalidate()
|
self.longPressTimer?.invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func startLongTapTimer() {
|
|
||||||
self.longTapTimer?.invalidate()
|
|
||||||
let longTapTimer = SwiftSignalKit.Timer(timeout: 0.25, repeat: false, completion: { [weak self] in
|
|
||||||
self?.longTapTimerFired()
|
|
||||||
}, queue: Queue.mainQueue())
|
|
||||||
self.longTapTimer = longTapTimer
|
|
||||||
longTapTimer.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func stopLongTapTimer() {
|
|
||||||
self.itemNode = nil
|
|
||||||
self.longTapTimer?.invalidate()
|
|
||||||
self.longTapTimer = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
private func startLongPressTimer() {
|
private func startLongPressTimer() {
|
||||||
self.longPressTimer?.invalidate()
|
self.longPressTimer?.invalidate()
|
||||||
let longPressTimer = SwiftSignalKit.Timer(timeout: 0.6, repeat: false, completion: { [weak self] in
|
let longPressTimer = SwiftSignalKit.Timer(timeout: 0.3, repeat: false, completion: { [weak self] in
|
||||||
self?.longPressTimerFired()
|
self?.longPressTimerFired()
|
||||||
}, queue: Queue.mainQueue())
|
}, queue: Queue.mainQueue())
|
||||||
self.longPressTimer = longPressTimer
|
self.longPressTimer = longPressTimer
|
||||||
@ -706,22 +689,11 @@ private class ReorderingGestureRecognizer: UIGestureRecognizer {
|
|||||||
super.reset()
|
super.reset()
|
||||||
|
|
||||||
self.itemNode = nil
|
self.itemNode = nil
|
||||||
self.stopLongTapTimer()
|
|
||||||
self.stopLongPressTimer()
|
self.stopLongPressTimer()
|
||||||
self.initialLocation = nil
|
self.initialLocation = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
private func longTapTimerFired() {
|
|
||||||
guard let location = self.initialLocation else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
self.longTapTimer?.invalidate()
|
|
||||||
self.longTapTimer = nil
|
|
||||||
|
|
||||||
self.willBegin(location)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func longPressTimerFired() {
|
private func longPressTimerFired() {
|
||||||
guard let _ = self.initialLocation else {
|
guard let _ = self.initialLocation else {
|
||||||
return
|
return
|
||||||
@ -730,13 +702,12 @@ private class ReorderingGestureRecognizer: UIGestureRecognizer {
|
|||||||
self.state = .began
|
self.state = .began
|
||||||
self.longPressTimer?.invalidate()
|
self.longPressTimer?.invalidate()
|
||||||
self.longPressTimer = nil
|
self.longPressTimer = nil
|
||||||
self.longTapTimer?.invalidate()
|
|
||||||
self.longTapTimer = nil
|
|
||||||
if let itemNode = self.itemNode {
|
if let itemNode = self.itemNode {
|
||||||
self.began(itemNode)
|
self.began(itemNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var currentItemNode: ASDisplayNode?
|
||||||
override public func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
|
override public func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||||
super.touchesBegan(touches, with: event)
|
super.touchesBegan(touches, with: event)
|
||||||
|
|
||||||
@ -750,10 +721,12 @@ private class ReorderingGestureRecognizer: UIGestureRecognizer {
|
|||||||
if let location = touches.first?.location(in: self.view) {
|
if let location = touches.first?.location(in: self.view) {
|
||||||
let (allowed, requiresLongPress, itemNode) = self.shouldBegin(location)
|
let (allowed, requiresLongPress, itemNode) = self.shouldBegin(location)
|
||||||
if allowed {
|
if allowed {
|
||||||
|
if let itemNode = itemNode {
|
||||||
|
itemNode.layer.animateScale(from: 1.0, to: 0.98, duration: 0.2, delay: 0.1)
|
||||||
|
}
|
||||||
self.itemNode = itemNode
|
self.itemNode = itemNode
|
||||||
self.initialLocation = location
|
self.initialLocation = location
|
||||||
if requiresLongPress {
|
if requiresLongPress {
|
||||||
self.startLongTapTimer()
|
|
||||||
self.startLongPressTimer()
|
self.startLongPressTimer()
|
||||||
} else {
|
} else {
|
||||||
self.state = .began
|
self.state = .began
|
||||||
@ -775,7 +748,6 @@ private class ReorderingGestureRecognizer: UIGestureRecognizer {
|
|||||||
|
|
||||||
self.initialLocation = nil
|
self.initialLocation = nil
|
||||||
|
|
||||||
self.stopLongTapTimer()
|
|
||||||
if self.longPressTimer != nil {
|
if self.longPressTimer != nil {
|
||||||
self.stopLongPressTimer()
|
self.stopLongPressTimer()
|
||||||
self.state = .failed
|
self.state = .failed
|
||||||
@ -795,7 +767,6 @@ private class ReorderingGestureRecognizer: UIGestureRecognizer {
|
|||||||
|
|
||||||
self.initialLocation = nil
|
self.initialLocation = nil
|
||||||
|
|
||||||
self.stopLongTapTimer()
|
|
||||||
if self.longPressTimer != nil {
|
if self.longPressTimer != nil {
|
||||||
self.stopLongPressTimer()
|
self.stopLongPressTimer()
|
||||||
self.state = .failed
|
self.state = .failed
|
||||||
@ -818,7 +789,8 @@ private class ReorderingGestureRecognizer: UIGestureRecognizer {
|
|||||||
let dY = touchLocation.y - initialTapLocation.y
|
let dY = touchLocation.y - initialTapLocation.y
|
||||||
|
|
||||||
if dX * dX + dY * dY > 3.0 * 3.0 {
|
if dX * dX + dY * dY > 3.0 * 3.0 {
|
||||||
self.stopLongTapTimer()
|
self.itemNode?.layer.removeAllAnimations()
|
||||||
|
|
||||||
self.stopLongPressTimer()
|
self.stopLongPressTimer()
|
||||||
self.initialLocation = nil
|
self.initialLocation = nil
|
||||||
self.state = .failed
|
self.state = .failed
|
||||||
@ -907,8 +879,8 @@ private final class ReorderingItemNode: ASDisplayNode {
|
|||||||
self.copyView.shadow.frame = CGRect(origin: CGPoint(x: -30.0, y: -30.0), size: CGSize(width: itemNode.bounds.size.width + 60.0, height: itemNode.bounds.size.height + 60.0))
|
self.copyView.shadow.frame = CGRect(origin: CGPoint(x: -30.0, y: -30.0), size: CGSize(width: itemNode.bounds.size.width + 60.0, height: itemNode.bounds.size.height + 60.0))
|
||||||
self.copyView.shadow.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
|
self.copyView.shadow.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
|
||||||
|
|
||||||
self.copyView.snapshotView?.layer.animateScale(from: 1.0, to: 1.05, duration: 0.25, removeOnCompletion: false)
|
self.copyView.snapshotView?.layer.animateScale(from: 1.0, to: 1.05, duration: 0.2, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
||||||
self.copyView.shadow.layer.animateScale(from: 1.0, to: 1.05, duration: 0.25, removeOnCompletion: false)
|
self.copyView.shadow.layer.animateScale(from: 1.0, to: 1.05, duration: 0.2, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateOffset(offset: CGPoint) {
|
func updateOffset(offset: CGPoint) {
|
||||||
|
@ -1322,7 +1322,7 @@ private func addContactToExisting(context: AccountContext, parentController: Vie
|
|||||||
(parentController.navigationController as? NavigationController)?.pushViewController(contactsController)
|
(parentController.navigationController as? NavigationController)?.pushViewController(contactsController)
|
||||||
let _ = (contactsController.result
|
let _ = (contactsController.result
|
||||||
|> deliverOnMainQueue).start(next: { result in
|
|> deliverOnMainQueue).start(next: { result in
|
||||||
if let (peers, _, _, _) = result, let peer = peers.first {
|
if let (peers, _, _, _, _) = result, let peer = peers.first {
|
||||||
let dataSignal: Signal<(Peer?, DeviceContactStableId?), NoError>
|
let dataSignal: Signal<(Peer?, DeviceContactStableId?), NoError>
|
||||||
switch peer {
|
switch peer {
|
||||||
case let .peer(contact, _, _):
|
case let .peer(contact, _, _):
|
||||||
|
@ -713,6 +713,7 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||||||
public var textReturned: ((String) -> Void)?
|
public var textReturned: ((String) -> Void)?
|
||||||
public var clearPrefix: (() -> Void)?
|
public var clearPrefix: (() -> Void)?
|
||||||
public var clearTokens: (() -> Void)?
|
public var clearTokens: (() -> Void)?
|
||||||
|
public var focusUpdated: ((Bool) -> Void)?
|
||||||
|
|
||||||
public var tokensUpdated: (([SearchBarToken]) -> Void)?
|
public var tokensUpdated: (([SearchBarToken]) -> Void)?
|
||||||
|
|
||||||
@ -1106,6 +1107,10 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||||||
self.cancelButton.layer.animatePosition(from: self.cancelButton.layer.position, to: CGPoint(x: self.bounds.size.width + cancelButtonFrame.size.width / 2.0, y: targetTextBackgroundFrame.midY), duration: duration, timingFunction: timingFunction, removeOnCompletion: false)
|
self.cancelButton.layer.animatePosition(from: self.cancelButton.layer.position, to: CGPoint(x: self.bounds.size.width + cancelButtonFrame.size.width / 2.0, y: targetTextBackgroundFrame.midY), duration: duration, timingFunction: timingFunction, removeOnCompletion: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||||
|
self.focusUpdated?(true)
|
||||||
|
}
|
||||||
|
|
||||||
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
||||||
if let _ = self.textField.selectedTokenIndex {
|
if let _ = self.textField.selectedTokenIndex {
|
||||||
if !string.isEmpty {
|
if !string.isEmpty {
|
||||||
@ -1137,6 +1142,7 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func textFieldDidEndEditing(_ textField: UITextField) {
|
public func textFieldDidEndEditing(_ textField: UITextField) {
|
||||||
|
self.focusUpdated?(false)
|
||||||
self.textField.selectedTokenIndex = nil
|
self.textField.selectedTokenIndex = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,9 @@ private class MediaHeaderItemNode: ASDisplayNode {
|
|||||||
let titleText: String = author.flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? ""
|
let titleText: String = author.flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? ""
|
||||||
let subtitleText: String
|
let subtitleText: String
|
||||||
if let peer = peer {
|
if let peer = peer {
|
||||||
if peer is TelegramGroup || peer is TelegramChannel {
|
if let peer = peer as? TelegramChannel, case .broadcast = peer.info {
|
||||||
|
subtitleText = strings.MusicPlayer_VoiceNote
|
||||||
|
} else if peer is TelegramGroup || peer is TelegramChannel {
|
||||||
subtitleText = EnginePeer(peer).displayTitle(strings: strings, displayOrder: nameDisplayOrder)
|
subtitleText = EnginePeer(peer).displayTitle(strings: strings, displayOrder: nameDisplayOrder)
|
||||||
} else {
|
} else {
|
||||||
subtitleText = strings.MusicPlayer_VoiceNote
|
subtitleText = strings.MusicPlayer_VoiceNote
|
||||||
|
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Animated.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Animated.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "attach_animated.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
173
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Animated.imageset/attach_animated.pdf
vendored
Normal file
173
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Animated.imageset/attach_animated.pdf
vendored
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
%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 6.629883 6.766602 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
11.547852 0.000000 m
|
||||||
|
11.988281 0.000000 12.342773 0.322266 12.493164 0.623047 c
|
||||||
|
6.724609 10.581055 l
|
||||||
|
6.638672 10.731445 6.574219 10.871094 6.574219 10.989258 c
|
||||||
|
6.574219 11.107422 6.638672 11.247070 6.724609 11.397461 c
|
||||||
|
12.493164 21.355469 l
|
||||||
|
12.342773 21.656250 11.988281 21.978516 11.547852 21.978516 c
|
||||||
|
11.214844 21.978516 10.838867 21.785156 10.602539 21.387695 c
|
||||||
|
5.156250 12.160156 l
|
||||||
|
4.876953 11.708984 4.694336 11.386719 4.694336 10.989258 c
|
||||||
|
4.694336 10.602539 4.876953 10.269531 5.156250 9.818359 c
|
||||||
|
10.613281 0.590820 l
|
||||||
|
10.860352 0.182617 11.214844 0.000000 11.547852 0.000000 c
|
||||||
|
h
|
||||||
|
16.918945 0.010742 m
|
||||||
|
17.509766 0.010742 17.896484 0.354492 18.401367 1.213867 c
|
||||||
|
23.299805 9.625000 l
|
||||||
|
23.600586 10.140625 23.740234 10.559570 23.740234 10.989258 c
|
||||||
|
23.740234 11.429688 23.600586 11.837891 23.299805 12.353516 c
|
||||||
|
18.401367 20.764648 l
|
||||||
|
17.896484 21.624023 17.509766 21.967773 16.918945 21.967773 c
|
||||||
|
16.328125 21.967773 15.941406 21.624023 15.425781 20.764648 c
|
||||||
|
10.538086 12.353516 l
|
||||||
|
10.226562 11.837891 10.097656 11.429688 10.097656 10.989258 c
|
||||||
|
10.097656 10.559570 10.237305 10.140625 10.538086 9.625000 c
|
||||||
|
15.425781 1.213867 l
|
||||||
|
15.941406 0.354492 16.328125 0.010742 16.918945 0.010742 c
|
||||||
|
h
|
||||||
|
6.294922 20.356445 m
|
||||||
|
6.681641 20.356445 6.993164 20.667969 6.993164 21.054688 c
|
||||||
|
6.993164 21.452148 6.681641 21.763672 6.294922 21.763672 c
|
||||||
|
5.897461 21.763672 5.585938 21.452148 5.585938 21.054688 c
|
||||||
|
5.585938 20.667969 5.897461 20.356445 6.294922 20.356445 c
|
||||||
|
h
|
||||||
|
5.177734 18.369141 m
|
||||||
|
5.575195 18.369141 5.886719 18.680664 5.886719 19.067383 c
|
||||||
|
5.886719 19.464844 5.575195 19.776367 5.177734 19.776367 c
|
||||||
|
4.791016 19.776367 4.479492 19.464844 4.479492 19.067383 c
|
||||||
|
4.479492 18.680664 4.791016 18.369141 5.177734 18.369141 c
|
||||||
|
h
|
||||||
|
16.918945 2.255859 m
|
||||||
|
16.865234 2.255859 16.833008 2.288086 16.811523 2.341797 c
|
||||||
|
12.127930 10.516602 l
|
||||||
|
12.020508 10.688477 11.966797 10.838867 11.966797 10.989258 c
|
||||||
|
11.966797 11.139648 12.020508 11.290039 12.117188 11.461914 c
|
||||||
|
16.811523 19.647461 l
|
||||||
|
16.833008 19.690430 16.865234 19.722656 16.918945 19.722656 c
|
||||||
|
16.972656 19.722656 16.994141 19.690430 17.026367 19.647461 c
|
||||||
|
21.709961 11.461914 l
|
||||||
|
21.817383 11.290039 21.860352 11.139648 21.860352 10.989258 c
|
||||||
|
21.860352 10.838867 21.817383 10.688477 21.709961 10.516602 c
|
||||||
|
17.026367 2.341797 l
|
||||||
|
16.994141 2.288086 16.972656 2.255859 16.918945 2.255859 c
|
||||||
|
h
|
||||||
|
4.060547 16.360352 m
|
||||||
|
4.458008 16.360352 4.769531 16.682617 4.769531 17.069336 c
|
||||||
|
4.769531 17.456055 4.458008 17.778320 4.060547 17.778320 c
|
||||||
|
3.673828 17.778320 3.362305 17.456055 3.362305 17.069336 c
|
||||||
|
3.362305 16.682617 3.673828 16.360352 4.060547 16.360352 c
|
||||||
|
h
|
||||||
|
2.932617 14.383789 m
|
||||||
|
3.330078 14.383789 3.641602 14.695312 3.641602 15.092773 c
|
||||||
|
3.641602 15.479492 3.330078 15.791016 2.932617 15.791016 c
|
||||||
|
2.545898 15.791016 2.234375 15.479492 2.234375 15.092773 c
|
||||||
|
2.234375 14.695312 2.545898 14.383789 2.932617 14.383789 c
|
||||||
|
h
|
||||||
|
1.826172 12.385742 m
|
||||||
|
2.212891 12.385742 2.524414 12.697266 2.524414 13.083984 c
|
||||||
|
2.524414 13.481445 2.212891 13.792969 1.826172 13.792969 c
|
||||||
|
1.439453 13.792969 1.117188 13.481445 1.117188 13.083984 c
|
||||||
|
1.117188 12.697266 1.439453 12.385742 1.826172 12.385742 c
|
||||||
|
h
|
||||||
|
0.708984 10.398438 m
|
||||||
|
1.095703 10.398438 1.407227 10.709961 1.407227 11.096680 c
|
||||||
|
1.407227 11.494141 1.095703 11.805664 0.708984 11.805664 c
|
||||||
|
0.311523 11.805664 0.000000 11.494141 0.000000 11.096680 c
|
||||||
|
0.000000 10.709961 0.311523 10.398438 0.708984 10.398438 c
|
||||||
|
h
|
||||||
|
1.826172 8.411133 m
|
||||||
|
2.212891 8.411133 2.524414 8.722656 2.524414 9.109375 c
|
||||||
|
2.524414 9.506836 2.212891 9.818359 1.826172 9.818359 c
|
||||||
|
1.439453 9.818359 1.117188 9.506836 1.117188 9.109375 c
|
||||||
|
1.117188 8.722656 1.439453 8.411133 1.826172 8.411133 c
|
||||||
|
h
|
||||||
|
2.932617 6.402344 m
|
||||||
|
3.330078 6.402344 3.641602 6.724609 3.641602 7.111328 c
|
||||||
|
3.641602 7.498047 3.330078 7.820312 2.932617 7.820312 c
|
||||||
|
2.545898 7.820312 2.234375 7.498047 2.234375 7.111328 c
|
||||||
|
2.234375 6.724609 2.545898 6.402344 2.932617 6.402344 c
|
||||||
|
h
|
||||||
|
4.060547 4.425781 m
|
||||||
|
4.458008 4.425781 4.769531 4.748047 4.769531 5.134766 c
|
||||||
|
4.769531 5.521484 4.458008 5.843750 4.060547 5.843750 c
|
||||||
|
3.673828 5.843750 3.362305 5.521484 3.362305 5.134766 c
|
||||||
|
3.362305 4.748047 3.673828 4.425781 4.060547 4.425781 c
|
||||||
|
h
|
||||||
|
5.177734 2.438477 m
|
||||||
|
5.575195 2.438477 5.886719 2.750000 5.886719 3.147461 c
|
||||||
|
5.886719 3.534180 5.575195 3.845703 5.177734 3.845703 c
|
||||||
|
4.791016 3.845703 4.479492 3.534180 4.479492 3.147461 c
|
||||||
|
4.479492 2.750000 4.791016 2.438477 5.177734 2.438477 c
|
||||||
|
h
|
||||||
|
6.294922 0.440430 m
|
||||||
|
6.681641 0.440430 6.993164 0.751953 6.993164 1.149414 c
|
||||||
|
6.993164 1.546875 6.681641 1.858398 6.294922 1.858398 c
|
||||||
|
5.897461 1.858398 5.585938 1.546875 5.585938 1.149414 c
|
||||||
|
5.585938 0.751953 5.897461 0.440430 6.294922 0.440430 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
4693
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 36.000000 36.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
|
||||||
|
0000004783 00000 n
|
||||||
|
0000004806 00000 n
|
||||||
|
0000004979 00000 n
|
||||||
|
0000005053 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
5112
|
||||||
|
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Burst.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Burst.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "attach_bursts.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
113
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Burst.imageset/attach_bursts.pdf
vendored
Normal file
113
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Burst.imageset/attach_bursts.pdf
vendored
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
%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 7.929688 5.337891 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
1.106445 5.102539 m
|
||||||
|
1.299805 5.102539 1.525391 5.166992 1.740234 5.317383 c
|
||||||
|
1.740234 16.811523 l
|
||||||
|
1.740234 17.198242 1.815430 17.348633 2.148438 17.531250 c
|
||||||
|
12.106445 23.267578 l
|
||||||
|
12.149414 23.976562 11.687500 24.416992 11.085938 24.416992 c
|
||||||
|
10.806641 24.416992 10.505859 24.341797 10.183594 24.148438 c
|
||||||
|
1.170898 18.970703 l
|
||||||
|
0.118164 18.358398 0.000000 18.165039 0.000000 16.940430 c
|
||||||
|
0.000000 6.660156 l
|
||||||
|
0.000000 5.736328 0.440430 5.102539 1.106445 5.102539 c
|
||||||
|
h
|
||||||
|
5.392578 2.621094 m
|
||||||
|
5.596680 2.621094 5.811523 2.685547 6.026367 2.835938 c
|
||||||
|
6.026367 14.330078 l
|
||||||
|
6.026367 14.749023 6.090820 14.856445 6.445312 15.049805 c
|
||||||
|
16.403320 20.796875 l
|
||||||
|
16.435547 21.495117 15.995117 21.946289 15.361328 21.946289 c
|
||||||
|
15.092773 21.946289 14.791992 21.860352 14.469727 21.688477 c
|
||||||
|
5.457031 16.500000 l
|
||||||
|
4.404297 15.898438 4.275391 15.672852 4.275391 14.469727 c
|
||||||
|
4.275391 4.178711 l
|
||||||
|
4.275391 3.254883 4.748047 2.621094 5.392578 2.621094 c
|
||||||
|
h
|
||||||
|
10.000977 0.000000 m
|
||||||
|
10.376953 0.000000 10.828125 0.150391 11.365234 0.451172 c
|
||||||
|
19.787109 5.285156 l
|
||||||
|
20.775391 5.854492 21.129883 6.445312 21.129883 7.648438 c
|
||||||
|
21.129883 17.380859 l
|
||||||
|
21.129883 18.669922 20.678711 19.325195 19.873047 19.325195 c
|
||||||
|
19.507812 19.325195 19.067383 19.185547 18.562500 18.895508 c
|
||||||
|
10.119141 14.029297 l
|
||||||
|
9.109375 13.438477 8.754883 12.836914 8.754883 11.666016 c
|
||||||
|
8.754883 1.933594 l
|
||||||
|
8.754883 0.687500 9.184570 0.000000 10.000977 0.000000 c
|
||||||
|
h
|
||||||
|
10.581055 2.094727 m
|
||||||
|
10.516602 2.105469 10.505859 2.137695 10.505859 2.212891 c
|
||||||
|
10.581055 11.633789 l
|
||||||
|
10.581055 12.041992 10.699219 12.256836 11.053711 12.460938 c
|
||||||
|
19.185547 17.241211 l
|
||||||
|
19.228516 17.262695 19.260742 17.262695 19.292969 17.251953 c
|
||||||
|
19.346680 17.241211 19.368164 17.208984 19.368164 17.133789 c
|
||||||
|
19.335938 7.680664 l
|
||||||
|
19.335938 7.326172 19.217773 7.057617 18.863281 6.842773 c
|
||||||
|
10.688477 2.105469 l
|
||||||
|
10.645508 2.083984 10.613281 2.083984 10.581055 2.094727 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
1984
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 36.000000 36.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
|
||||||
|
0000002074 00000 n
|
||||||
|
0000002097 00000 n
|
||||||
|
0000002270 00000 n
|
||||||
|
0000002344 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
2403
|
||||||
|
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Cinematic.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Cinematic.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "attach_cinematic.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
485
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Cinematic.imageset/attach_cinematic.pdf
vendored
Normal file
485
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Cinematic.imageset/attach_cinematic.pdf
vendored
Normal file
@ -0,0 +1,485 @@
|
|||||||
|
%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 5.592773 8.925781 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
4.189453 0.000000 m
|
||||||
|
15.415039 0.000000 l
|
||||||
|
18.036133 0.000000 19.604492 1.525391 19.604492 4.146484 c
|
||||||
|
19.604492 5.618164 l
|
||||||
|
23.665039 2.180664 l
|
||||||
|
24.094727 1.826172 24.567383 1.579102 25.007812 1.579102 c
|
||||||
|
25.953125 1.579102 26.576172 2.277344 26.576172 3.276367 c
|
||||||
|
26.576172 14.383789 l
|
||||||
|
26.576172 15.382812 25.953125 16.081055 25.007812 16.081055 c
|
||||||
|
24.567383 16.081055 24.094727 15.833984 23.665039 15.479492 c
|
||||||
|
19.604492 12.041992 l
|
||||||
|
19.604492 13.524414 l
|
||||||
|
19.604492 16.134766 18.036133 17.660156 15.415039 17.660156 c
|
||||||
|
4.189453 17.660156 l
|
||||||
|
1.686523 17.660156 0.000000 16.134766 0.000000 13.524414 c
|
||||||
|
0.000000 4.146484 l
|
||||||
|
0.000000 1.525391 1.568359 0.000000 4.189453 0.000000 c
|
||||||
|
h
|
||||||
|
4.490234 1.622070 m
|
||||||
|
2.728516 1.622070 1.729492 2.535156 1.729492 4.393555 c
|
||||||
|
1.729492 13.266602 l
|
||||||
|
1.729492 15.135742 2.728516 16.048828 4.490234 16.048828 c
|
||||||
|
15.114258 16.048828 l
|
||||||
|
16.865234 16.048828 17.875000 15.135742 17.875000 13.266602 c
|
||||||
|
17.875000 4.393555 l
|
||||||
|
17.875000 2.535156 16.865234 1.622070 15.114258 1.622070 c
|
||||||
|
4.490234 1.622070 l
|
||||||
|
h
|
||||||
|
24.470703 3.641602 m
|
||||||
|
19.604492 7.659180 l
|
||||||
|
19.604492 10.000977 l
|
||||||
|
24.470703 14.018555 l
|
||||||
|
24.567383 14.093750 24.631836 14.147461 24.728516 14.147461 c
|
||||||
|
24.857422 14.147461 24.911133 14.040039 24.911133 13.889648 c
|
||||||
|
24.911133 3.770508 l
|
||||||
|
24.911133 3.620117 24.857422 3.523438 24.728516 3.523438 c
|
||||||
|
24.631836 3.523438 24.567383 3.577148 24.470703 3.641602 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 10.000000 11.225647 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
0.450664 7.941575 m
|
||||||
|
0.693185 7.941575 0.952624 8.012091 1.149094 8.213968 c
|
||||||
|
1.343381 8.413603 1.406961 8.670843 1.406961 8.903505 c
|
||||||
|
0.406961 8.903505 l
|
||||||
|
0.406961 8.874201 0.402920 8.864758 0.404416 8.869144 c
|
||||||
|
0.406454 8.875122 0.414068 8.892520 0.432455 8.911413 c
|
||||||
|
0.451071 8.930541 0.469642 8.939795 0.478687 8.943048 c
|
||||||
|
0.485932 8.945654 0.478955 8.941575 0.450664 8.941575 c
|
||||||
|
0.450664 7.941575 l
|
||||||
|
h
|
||||||
|
1.406961 8.903505 m
|
||||||
|
1.406961 10.232964 l
|
||||||
|
0.406961 10.232964 l
|
||||||
|
0.406961 8.903505 l
|
||||||
|
1.406961 8.903505 l
|
||||||
|
h
|
||||||
|
1.406961 10.232964 m
|
||||||
|
1.406961 10.441644 1.461145 10.516622 1.485847 10.541323 c
|
||||||
|
1.510620 10.566097 1.582848 10.617392 1.780123 10.617392 c
|
||||||
|
1.780123 11.617392 l
|
||||||
|
1.414067 11.617392 1.049714 11.519404 0.778740 11.248430 c
|
||||||
|
0.507693 10.977384 0.406961 10.610147 0.406961 10.232964 c
|
||||||
|
1.406961 10.232964 l
|
||||||
|
h
|
||||||
|
1.780123 10.617392 m
|
||||||
|
3.143381 10.617392 l
|
||||||
|
3.143381 11.617392 l
|
||||||
|
1.780123 11.617392 l
|
||||||
|
1.780123 10.617392 l
|
||||||
|
h
|
||||||
|
3.143381 10.617392 m
|
||||||
|
3.381150 10.617392 3.639620 10.683693 3.838258 10.880542 c
|
||||||
|
4.037554 11.078042 4.105311 11.336237 4.105311 11.573689 c
|
||||||
|
3.105311 11.573689 l
|
||||||
|
3.105311 11.546071 3.101378 11.538866 3.103720 11.545491 c
|
||||||
|
3.106672 11.553840 3.115477 11.572130 3.134358 11.590840 c
|
||||||
|
3.153171 11.609484 3.170862 11.617524 3.177536 11.619841 c
|
||||||
|
3.182541 11.621578 3.173327 11.617392 3.143381 11.617392 c
|
||||||
|
3.143381 10.617392 l
|
||||||
|
h
|
||||||
|
4.105311 11.573689 m
|
||||||
|
4.105311 11.811355 4.037323 12.070365 3.834985 12.267233 c
|
||||||
|
3.634857 12.461953 3.376599 12.524353 3.143381 12.524353 c
|
||||||
|
3.143381 11.524353 l
|
||||||
|
3.175038 11.524353 3.185540 11.520061 3.181437 11.521447 c
|
||||||
|
3.175622 11.523413 3.157468 11.531206 3.137630 11.550508 c
|
||||||
|
3.117559 11.570037 3.107757 11.589691 3.104216 11.599611 c
|
||||||
|
3.101361 11.607611 3.105311 11.601369 3.105311 11.573689 c
|
||||||
|
4.105311 11.573689 l
|
||||||
|
h
|
||||||
|
3.143381 12.524353 m
|
||||||
|
1.768856 12.524353 l
|
||||||
|
1.768856 11.524353 l
|
||||||
|
3.143381 11.524353 l
|
||||||
|
3.143381 12.524353 l
|
||||||
|
h
|
||||||
|
1.768856 12.524353 m
|
||||||
|
1.104903 12.524353 0.514360 12.360654 0.092355 11.945700 c
|
||||||
|
-0.331199 11.529222 -0.500000 10.943424 -0.500000 10.283664 c
|
||||||
|
0.500000 10.283664 l
|
||||||
|
0.500000 10.784363 0.626947 11.068910 0.793481 11.232662 c
|
||||||
|
0.961564 11.397937 1.255449 11.524353 1.768856 11.524353 c
|
||||||
|
1.768856 12.524353 l
|
||||||
|
h
|
||||||
|
-0.500000 10.283664 m
|
||||||
|
-0.500000 8.903505 l
|
||||||
|
0.500000 8.903505 l
|
||||||
|
0.500000 10.283664 l
|
||||||
|
-0.500000 10.283664 l
|
||||||
|
h
|
||||||
|
-0.500000 8.903505 m
|
||||||
|
-0.500000 8.666346 -0.432617 8.411142 -0.240725 8.213968 c
|
||||||
|
-0.046923 8.014833 0.208894 7.941575 0.450664 7.941575 c
|
||||||
|
0.450664 8.941575 l
|
||||||
|
0.427263 8.941575 0.422817 8.945058 0.431106 8.942020 c
|
||||||
|
0.440899 8.938431 0.458558 8.929247 0.475915 8.911413 c
|
||||||
|
0.493081 8.893774 0.500330 8.877576 0.502352 8.871754 c
|
||||||
|
0.503901 8.867291 0.500000 8.876007 0.500000 8.903505 c
|
||||||
|
-0.500000 8.903505 l
|
||||||
|
h
|
||||||
|
10.573703 7.941575 m
|
||||||
|
10.816223 7.941575 11.075663 8.012091 11.272133 8.213969 c
|
||||||
|
11.466420 8.413603 11.530000 8.670844 11.530000 8.903505 c
|
||||||
|
10.530000 8.903505 l
|
||||||
|
10.530000 8.874201 10.525958 8.864758 10.527454 8.869144 c
|
||||||
|
10.529492 8.875122 10.537107 8.892520 10.555493 8.911412 c
|
||||||
|
10.574109 8.930541 10.592681 8.939795 10.601726 8.943048 c
|
||||||
|
10.608971 8.945654 10.601994 8.941575 10.573703 8.941575 c
|
||||||
|
10.573703 7.941575 l
|
||||||
|
h
|
||||||
|
11.530000 8.903505 m
|
||||||
|
11.530000 10.283664 l
|
||||||
|
10.530000 10.283664 l
|
||||||
|
10.530000 8.903505 l
|
||||||
|
11.530000 8.903505 l
|
||||||
|
h
|
||||||
|
11.530000 10.283664 m
|
||||||
|
11.530000 10.943424 11.361198 11.529222 10.937644 11.945700 c
|
||||||
|
10.515639 12.360654 9.925097 12.524353 9.261144 12.524353 c
|
||||||
|
9.261144 11.524353 l
|
||||||
|
9.774550 11.524353 10.068436 11.397937 10.236519 11.232662 c
|
||||||
|
10.403052 11.068910 10.530000 10.784363 10.530000 10.283664 c
|
||||||
|
11.530000 10.283664 l
|
||||||
|
h
|
||||||
|
9.261144 12.524353 m
|
||||||
|
7.880985 12.524353 l
|
||||||
|
7.880985 11.524353 l
|
||||||
|
9.261144 11.524353 l
|
||||||
|
9.261144 12.524353 l
|
||||||
|
h
|
||||||
|
7.880985 12.524353 m
|
||||||
|
7.648191 12.524353 7.391307 12.460656 7.192692 12.265653 c
|
||||||
|
6.992592 12.069190 6.924688 11.811304 6.924688 11.573689 c
|
||||||
|
7.924688 11.573689 l
|
||||||
|
7.924688 11.601334 7.928629 11.607865 7.925930 11.600269 c
|
||||||
|
7.922583 11.590851 7.913094 11.571540 7.893283 11.552089 c
|
||||||
|
7.873628 11.532791 7.855208 11.524535 7.848195 11.522132 c
|
||||||
|
7.842865 11.520305 7.851656 11.524353 7.880985 11.524353 c
|
||||||
|
7.880985 12.524353 l
|
||||||
|
h
|
||||||
|
6.924688 11.573689 m
|
||||||
|
6.924688 11.336283 6.992366 11.079206 7.189434 10.882138 c
|
||||||
|
7.386502 10.685069 7.643578 10.617392 7.880985 10.617392 c
|
||||||
|
7.880985 11.617392 l
|
||||||
|
7.853402 11.617392 7.845911 11.621316 7.852134 11.619125 c
|
||||||
|
7.859986 11.616362 7.877925 11.607861 7.896541 11.589245 c
|
||||||
|
7.915157 11.570628 7.923658 11.552690 7.926422 11.544838 c
|
||||||
|
7.928613 11.538614 7.924688 11.546105 7.924688 11.573689 c
|
||||||
|
6.924688 11.573689 l
|
||||||
|
h
|
||||||
|
7.880985 10.617392 m
|
||||||
|
9.244244 10.617392 l
|
||||||
|
9.244244 11.617392 l
|
||||||
|
7.880985 11.617392 l
|
||||||
|
7.880985 10.617392 l
|
||||||
|
h
|
||||||
|
9.244244 10.617392 m
|
||||||
|
9.437582 10.617392 9.513561 10.566607 9.541740 10.538825 c
|
||||||
|
9.568624 10.512321 9.623038 10.436918 9.623038 10.232964 c
|
||||||
|
10.623038 10.232964 l
|
||||||
|
10.623038 10.614872 10.516905 10.981685 10.243814 11.250929 c
|
||||||
|
9.972020 11.518894 9.608603 11.617392 9.244244 11.617392 c
|
||||||
|
9.244244 10.617392 l
|
||||||
|
h
|
||||||
|
9.623038 10.232964 m
|
||||||
|
9.623038 8.903505 l
|
||||||
|
10.623038 8.903505 l
|
||||||
|
10.623038 10.232964 l
|
||||||
|
9.623038 10.232964 l
|
||||||
|
h
|
||||||
|
9.623038 8.903505 m
|
||||||
|
9.623038 8.666346 9.690422 8.411142 9.882315 8.213968 c
|
||||||
|
10.076117 8.014833 10.331933 7.941575 10.573703 7.941575 c
|
||||||
|
10.573703 8.941575 l
|
||||||
|
10.550302 8.941575 10.545856 8.945058 10.554144 8.942020 c
|
||||||
|
10.563938 8.938431 10.581596 8.929247 10.598953 8.911413 c
|
||||||
|
10.616119 8.893775 10.623368 8.877576 10.625390 8.871755 c
|
||||||
|
10.626940 8.867291 10.623038 8.876008 10.623038 8.903505 c
|
||||||
|
9.623038 8.903505 l
|
||||||
|
h
|
||||||
|
1.768856 0.499987 m
|
||||||
|
3.143381 0.499987 l
|
||||||
|
3.143381 1.499987 l
|
||||||
|
1.768856 1.499987 l
|
||||||
|
1.768856 0.499987 l
|
||||||
|
h
|
||||||
|
3.143381 0.499987 m
|
||||||
|
3.381126 0.499987 3.638457 0.566224 3.836632 0.760829 c
|
||||||
|
4.036100 0.956702 4.105311 1.213470 4.105311 1.450650 c
|
||||||
|
3.105311 1.450650 l
|
||||||
|
3.105311 1.425433 3.101656 1.419969 3.104469 1.427811 c
|
||||||
|
3.107882 1.437328 3.117153 1.455843 3.135983 1.474335 c
|
||||||
|
3.154683 1.492697 3.172005 1.500437 3.178184 1.502572 c
|
||||||
|
3.182789 1.504164 3.173292 1.499987 3.143381 1.499987 c
|
||||||
|
3.143381 0.499987 l
|
||||||
|
h
|
||||||
|
4.105311 1.450650 m
|
||||||
|
4.105311 1.688103 4.037554 1.946297 3.838258 2.143798 c
|
||||||
|
3.639621 2.340646 3.381150 2.406948 3.143381 2.406948 c
|
||||||
|
3.143381 1.406948 l
|
||||||
|
3.173327 1.406948 3.182540 1.402761 3.177535 1.404499 c
|
||||||
|
3.170861 1.406816 3.153170 1.414856 3.134358 1.433499 c
|
||||||
|
3.115477 1.452209 3.106672 1.470500 3.103720 1.478848 c
|
||||||
|
3.101378 1.485473 3.105311 1.478268 3.105311 1.450650 c
|
||||||
|
4.105311 1.450650 l
|
||||||
|
h
|
||||||
|
3.143381 2.406948 m
|
||||||
|
1.780123 2.406948 l
|
||||||
|
1.780123 1.406948 l
|
||||||
|
3.143381 1.406948 l
|
||||||
|
3.143381 2.406948 l
|
||||||
|
h
|
||||||
|
1.780123 2.406948 m
|
||||||
|
1.582848 2.406948 1.510620 2.458242 1.485847 2.483017 c
|
||||||
|
1.461145 2.507718 1.406961 2.582696 1.406961 2.791376 c
|
||||||
|
0.406961 2.791376 l
|
||||||
|
0.406961 2.414193 0.507693 2.046957 0.778740 1.775910 c
|
||||||
|
1.049714 1.504936 1.414067 1.406948 1.780123 1.406948 c
|
||||||
|
1.780123 2.406948 l
|
||||||
|
h
|
||||||
|
1.406961 2.791376 m
|
||||||
|
1.406961 4.120834 l
|
||||||
|
0.406961 4.120834 l
|
||||||
|
0.406961 2.791376 l
|
||||||
|
1.406961 2.791376 l
|
||||||
|
h
|
||||||
|
1.406961 4.120834 m
|
||||||
|
1.406961 4.358603 1.340660 4.617074 1.143812 4.815711 c
|
||||||
|
0.946311 5.015007 0.688117 5.082765 0.450664 5.082765 c
|
||||||
|
0.450664 4.082765 l
|
||||||
|
0.478281 4.082765 0.485486 4.078832 0.478862 4.081174 c
|
||||||
|
0.470513 4.084126 0.452223 4.092931 0.433512 4.111812 c
|
||||||
|
0.414869 4.130625 0.406829 4.148315 0.404512 4.154989 c
|
||||||
|
0.402775 4.159994 0.406961 4.150780 0.406961 4.120834 c
|
||||||
|
1.406961 4.120834 l
|
||||||
|
h
|
||||||
|
0.450664 5.082765 m
|
||||||
|
0.212998 5.082765 -0.046012 5.014776 -0.242880 4.812439 c
|
||||||
|
-0.437600 4.612310 -0.500000 4.354052 -0.500000 4.120834 c
|
||||||
|
0.500000 4.120834 l
|
||||||
|
0.500000 4.152492 0.504292 4.162993 0.502905 4.158891 c
|
||||||
|
0.500940 4.153075 0.493147 4.134922 0.473846 4.115084 c
|
||||||
|
0.454316 4.095012 0.434662 4.085211 0.424742 4.081670 c
|
||||||
|
0.416742 4.078815 0.422984 4.082765 0.450664 4.082765 c
|
||||||
|
0.450664 5.082765 l
|
||||||
|
h
|
||||||
|
-0.500000 4.120834 m
|
||||||
|
-0.500000 2.746309 l
|
||||||
|
0.500000 2.746309 l
|
||||||
|
0.500000 4.120834 l
|
||||||
|
-0.500000 4.120834 l
|
||||||
|
h
|
||||||
|
-0.500000 2.746309 m
|
||||||
|
-0.500000 2.084355 -0.331527 1.497156 0.091924 1.079769 c
|
||||||
|
0.514044 0.663693 1.104907 0.499987 1.768856 0.499987 c
|
||||||
|
1.768856 1.499987 l
|
||||||
|
1.255445 1.499987 0.961880 1.626395 0.793913 1.791957 c
|
||||||
|
0.627276 1.956208 0.500000 2.242170 0.500000 2.746309 c
|
||||||
|
-0.500000 2.746309 l
|
||||||
|
h
|
||||||
|
7.880985 0.499987 m
|
||||||
|
9.261144 0.499987 l
|
||||||
|
9.261144 1.499987 l
|
||||||
|
7.880985 1.499987 l
|
||||||
|
7.880985 0.499987 l
|
||||||
|
h
|
||||||
|
9.261144 0.499987 m
|
||||||
|
9.926300 0.499987 10.516878 0.665709 10.938506 1.082307 c
|
||||||
|
11.361227 1.499982 11.530000 2.086557 11.530000 2.746309 c
|
||||||
|
10.530000 2.746309 l
|
||||||
|
10.530000 2.245602 10.403025 1.959016 10.235657 1.793645 c
|
||||||
|
10.067197 1.627195 9.773346 1.499987 9.261144 1.499987 c
|
||||||
|
9.261144 0.499987 l
|
||||||
|
h
|
||||||
|
11.530000 2.746309 m
|
||||||
|
11.530000 4.120834 l
|
||||||
|
10.530000 4.120834 l
|
||||||
|
10.530000 2.746309 l
|
||||||
|
11.530000 2.746309 l
|
||||||
|
h
|
||||||
|
11.530000 4.120834 m
|
||||||
|
11.530000 4.358603 11.463698 4.617073 11.266850 4.815711 c
|
||||||
|
11.069350 5.015007 10.811155 5.082765 10.573703 5.082765 c
|
||||||
|
10.573703 4.082765 l
|
||||||
|
10.601320 4.082765 10.608525 4.078832 10.601901 4.081174 c
|
||||||
|
10.593552 4.084126 10.575261 4.092931 10.556551 4.111812 c
|
||||||
|
10.537908 4.130625 10.529867 4.148315 10.527551 4.154989 c
|
||||||
|
10.525813 4.159994 10.530000 4.150780 10.530000 4.120834 c
|
||||||
|
11.530000 4.120834 l
|
||||||
|
h
|
||||||
|
10.573703 5.082765 m
|
||||||
|
10.336037 5.082765 10.077027 5.014776 9.880158 4.812439 c
|
||||||
|
9.685439 4.612311 9.623038 4.354053 9.623038 4.120834 c
|
||||||
|
10.623038 4.120834 l
|
||||||
|
10.623038 4.152492 10.627330 4.162993 10.625944 4.158891 c
|
||||||
|
10.623979 4.153075 10.616185 4.134922 10.596884 4.115084 c
|
||||||
|
10.577354 4.095012 10.557701 4.085210 10.547780 4.081670 c
|
||||||
|
10.539782 4.078815 10.546023 4.082765 10.573703 4.082765 c
|
||||||
|
10.573703 5.082765 l
|
||||||
|
h
|
||||||
|
9.623038 4.120834 m
|
||||||
|
9.623038 2.791376 l
|
||||||
|
10.623038 2.791376 l
|
||||||
|
10.623038 4.120834 l
|
||||||
|
9.623038 4.120834 l
|
||||||
|
h
|
||||||
|
9.623038 2.791376 m
|
||||||
|
9.623038 2.587421 9.568624 2.512020 9.541740 2.485516 c
|
||||||
|
9.513561 2.457733 9.437582 2.406948 9.244244 2.406948 c
|
||||||
|
9.244244 1.406948 l
|
||||||
|
9.608603 1.406948 9.972020 1.505445 10.243814 1.773412 c
|
||||||
|
10.516905 2.042655 10.623038 2.409468 10.623038 2.791376 c
|
||||||
|
9.623038 2.791376 l
|
||||||
|
h
|
||||||
|
9.244244 2.406948 m
|
||||||
|
7.880985 2.406948 l
|
||||||
|
7.880985 1.406948 l
|
||||||
|
9.244244 1.406948 l
|
||||||
|
9.244244 2.406948 l
|
||||||
|
h
|
||||||
|
7.880985 2.406948 m
|
||||||
|
7.643578 2.406948 7.386502 2.339270 7.189434 2.142201 c
|
||||||
|
6.992366 1.945133 6.924688 1.688057 6.924688 1.450650 c
|
||||||
|
7.924688 1.450650 l
|
||||||
|
7.924688 1.478234 7.928613 1.485724 7.926422 1.479502 c
|
||||||
|
7.923658 1.471650 7.915157 1.453712 7.896542 1.435096 c
|
||||||
|
7.877926 1.416480 7.859987 1.407979 7.852135 1.405214 c
|
||||||
|
7.845911 1.403024 7.853402 1.406948 7.880985 1.406948 c
|
||||||
|
7.880985 2.406948 l
|
||||||
|
h
|
||||||
|
6.924688 1.450650 m
|
||||||
|
6.924688 1.213532 6.993807 0.957870 7.191052 0.762418 c
|
||||||
|
7.387669 0.567588 7.643617 0.499987 7.880985 0.499987 c
|
||||||
|
7.880985 1.499987 l
|
||||||
|
7.853435 1.499987 7.845659 1.503901 7.851480 1.501862 c
|
||||||
|
7.858835 1.499284 7.876413 1.491087 7.894923 1.472746 c
|
||||||
|
7.913496 1.454342 7.922459 1.436171 7.925679 1.427151 c
|
||||||
|
7.928335 1.419713 7.924688 1.425466 7.924688 1.450650 c
|
||||||
|
6.924688 1.450650 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 10.000000 11.225647 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
0.450664 8.441575 m
|
||||||
|
0.749229 8.441575 0.906961 8.610574 0.906961 8.903505 c
|
||||||
|
0.906961 10.232964 l
|
||||||
|
0.906961 10.818827 1.216793 11.117392 1.780123 11.117392 c
|
||||||
|
3.143381 11.117392 l
|
||||||
|
3.441946 11.117392 3.605311 11.280758 3.605311 11.573689 c
|
||||||
|
3.605311 11.866621 3.441946 12.024353 3.143381 12.024353 c
|
||||||
|
1.768856 12.024353 l
|
||||||
|
0.591496 12.024353 0.000000 11.444123 0.000000 10.283664 c
|
||||||
|
0.000000 8.903505 l
|
||||||
|
0.000000 8.610574 0.163366 8.441575 0.450664 8.441575 c
|
||||||
|
h
|
||||||
|
10.573703 8.441575 m
|
||||||
|
10.872268 8.441575 11.030000 8.610574 11.030000 8.903505 c
|
||||||
|
11.030000 10.283664 l
|
||||||
|
11.030000 11.444123 10.438503 12.024353 9.261144 12.024353 c
|
||||||
|
7.880985 12.024353 l
|
||||||
|
7.588054 12.024353 7.424688 11.866621 7.424688 11.573689 c
|
||||||
|
7.424688 11.280758 7.588054 11.117392 7.880985 11.117392 c
|
||||||
|
9.244244 11.117392 l
|
||||||
|
9.801940 11.117392 10.123038 10.818827 10.123038 10.232964 c
|
||||||
|
10.123038 8.903505 l
|
||||||
|
10.123038 8.610574 10.286405 8.441575 10.573703 8.441575 c
|
||||||
|
h
|
||||||
|
1.768856 0.999987 m
|
||||||
|
3.143381 0.999987 l
|
||||||
|
3.441946 0.999987 3.605311 1.163352 3.605311 1.450650 c
|
||||||
|
3.605311 1.743582 3.441946 1.906948 3.143381 1.906948 c
|
||||||
|
1.780123 1.906948 l
|
||||||
|
1.216793 1.906948 0.906961 2.205513 0.906961 2.791376 c
|
||||||
|
0.906961 4.120834 l
|
||||||
|
0.906961 4.419399 0.743595 4.582765 0.450664 4.582765 c
|
||||||
|
0.157732 4.582765 0.000000 4.419399 0.000000 4.120834 c
|
||||||
|
0.000000 2.746309 l
|
||||||
|
0.000000 1.580216 0.591496 0.999987 1.768856 0.999987 c
|
||||||
|
h
|
||||||
|
7.880985 0.999987 m
|
||||||
|
9.261144 0.999987 l
|
||||||
|
10.438503 0.999987 11.030000 1.585850 11.030000 2.746309 c
|
||||||
|
11.030000 4.120834 l
|
||||||
|
11.030000 4.419399 10.866634 4.582765 10.573703 4.582765 c
|
||||||
|
10.280771 4.582765 10.123038 4.419399 10.123038 4.120834 c
|
||||||
|
10.123038 2.791376 l
|
||||||
|
10.123038 2.205513 9.801940 1.906948 9.244244 1.906948 c
|
||||||
|
7.880985 1.906948 l
|
||||||
|
7.588054 1.906948 7.424688 1.743582 7.424688 1.450650 c
|
||||||
|
7.424688 1.163352 7.588054 0.999987 7.880985 0.999987 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
14103
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 36.000000 36.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
|
||||||
|
0000014193 00000 n
|
||||||
|
0000014217 00000 n
|
||||||
|
0000014390 00000 n
|
||||||
|
0000014464 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
14523
|
||||||
|
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Favorite.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Favorite.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "favefilled_24.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
75
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Favorite.imageset/favefilled_24.pdf
vendored
Normal file
75
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Favorite.imageset/favefilled_24.pdf
vendored
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
%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 3.500000 3.753906 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
8.500000 0.000054 m
|
||||||
|
8.718812 0.000054 9.030198 0.159956 9.282673 0.319857 c
|
||||||
|
13.987128 3.349560 17.000000 6.901045 17.000000 10.503025 c
|
||||||
|
17.000000 13.591639 14.870791 15.746094 12.186138 15.746094 c
|
||||||
|
10.511386 15.746094 9.257425 14.820352 8.500000 13.431738 c
|
||||||
|
7.759406 14.811935 6.497030 15.746094 4.822277 15.746094 c
|
||||||
|
2.137624 15.746094 0.000000 13.591639 0.000000 10.503025 c
|
||||||
|
0.000000 6.901045 3.012871 3.349560 7.717327 0.319857 c
|
||||||
|
7.978218 0.159956 8.289604 0.000054 8.500000 0.000054 c
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
615
|
||||||
|
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
|
||||||
|
0000000705 00000 n
|
||||||
|
0000000727 00000 n
|
||||||
|
0000000900 00000 n
|
||||||
|
0000000974 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
1033
|
||||||
|
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/LivePhoto.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/LivePhoto.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "attach_live.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
305
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/LivePhoto.imageset/attach_live.pdf
vendored
Normal file
305
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/LivePhoto.imageset/attach_live.pdf
vendored
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
%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 6.065430 5.799805 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
11.934570 22.751953 m
|
||||||
|
12.246094 22.751953 12.482422 22.999023 12.482422 23.299805 c
|
||||||
|
12.482422 23.600586 12.246094 23.869141 11.934570 23.869141 c
|
||||||
|
11.644531 23.869141 11.375977 23.600586 11.375977 23.299805 c
|
||||||
|
11.375977 22.999023 11.644531 22.751953 11.934570 22.751953 c
|
||||||
|
h
|
||||||
|
13.921875 22.580078 m
|
||||||
|
14.211914 22.580078 14.480469 22.837891 14.480469 23.127930 c
|
||||||
|
14.480469 23.428711 14.211914 23.697266 13.921875 23.697266 c
|
||||||
|
13.599609 23.697266 13.363281 23.428711 13.363281 23.127930 c
|
||||||
|
13.363281 22.837891 13.599609 22.580078 13.921875 22.580078 c
|
||||||
|
h
|
||||||
|
9.947266 22.580078 m
|
||||||
|
10.258789 22.580078 10.495117 22.837891 10.495117 23.127930 c
|
||||||
|
10.495117 23.428711 10.258789 23.697266 9.947266 23.697266 c
|
||||||
|
9.657227 23.697266 9.388672 23.428711 9.388672 23.127930 c
|
||||||
|
9.388672 22.837891 9.657227 22.580078 9.947266 22.580078 c
|
||||||
|
h
|
||||||
|
15.833984 22.075195 m
|
||||||
|
16.113281 22.075195 16.381836 22.322266 16.381836 22.612305 c
|
||||||
|
16.381836 22.913086 16.113281 23.181641 15.833984 23.181641 c
|
||||||
|
15.511719 23.181641 15.275391 22.913086 15.275391 22.612305 c
|
||||||
|
15.275391 22.322266 15.511719 22.075195 15.833984 22.075195 c
|
||||||
|
h
|
||||||
|
8.035156 22.075195 m
|
||||||
|
8.346680 22.075195 8.583008 22.322266 8.583008 22.612305 c
|
||||||
|
8.583008 22.913086 8.346680 23.181641 8.035156 23.181641 c
|
||||||
|
7.745117 23.181641 7.487305 22.913086 7.487305 22.612305 c
|
||||||
|
7.487305 22.322266 7.745117 22.075195 8.035156 22.075195 c
|
||||||
|
h
|
||||||
|
17.627930 21.226562 m
|
||||||
|
17.917969 21.226562 18.175781 21.473633 18.175781 21.774414 c
|
||||||
|
18.175781 22.075195 17.917969 22.333008 17.627930 22.333008 c
|
||||||
|
17.316406 22.333008 17.069336 22.075195 17.069336 21.774414 c
|
||||||
|
17.069336 21.473633 17.316406 21.226562 17.627930 21.226562 c
|
||||||
|
h
|
||||||
|
6.241211 21.226562 m
|
||||||
|
6.563477 21.226562 6.799805 21.473633 6.799805 21.774414 c
|
||||||
|
6.799805 22.075195 6.563477 22.333008 6.241211 22.333008 c
|
||||||
|
5.940430 22.333008 5.682617 22.075195 5.682617 21.774414 c
|
||||||
|
5.682617 21.473633 5.940430 21.226562 6.241211 21.226562 c
|
||||||
|
h
|
||||||
|
19.250000 20.087891 m
|
||||||
|
19.550781 20.087891 19.808594 20.345703 19.808594 20.625000 c
|
||||||
|
19.808594 20.936523 19.550781 21.194336 19.250000 21.194336 c
|
||||||
|
18.949219 21.194336 18.712891 20.936523 18.712891 20.625000 c
|
||||||
|
18.712891 20.345703 18.949219 20.087891 19.250000 20.087891 c
|
||||||
|
h
|
||||||
|
4.608398 20.087891 m
|
||||||
|
4.919922 20.087891 5.166992 20.345703 5.166992 20.625000 c
|
||||||
|
5.166992 20.936523 4.919922 21.194336 4.608398 21.194336 c
|
||||||
|
4.318359 21.194336 4.049805 20.936523 4.049805 20.625000 c
|
||||||
|
4.049805 20.345703 4.318359 20.087891 4.608398 20.087891 c
|
||||||
|
h
|
||||||
|
11.945312 3.254883 m
|
||||||
|
16.736328 3.254883 20.614258 7.122070 20.614258 11.934570 c
|
||||||
|
20.614258 16.704102 16.714844 20.603516 11.945312 20.603516 c
|
||||||
|
7.122070 20.603516 3.265625 16.736328 3.265625 11.934570 c
|
||||||
|
3.265625 7.100586 7.111328 3.254883 11.945312 3.254883 c
|
||||||
|
h
|
||||||
|
20.657227 18.691406 m
|
||||||
|
20.958008 18.691406 21.215820 18.938477 21.215820 19.228516 c
|
||||||
|
21.215820 19.540039 20.958008 19.797852 20.657227 19.797852 c
|
||||||
|
20.345703 19.797852 20.098633 19.540039 20.098633 19.228516 c
|
||||||
|
20.098633 18.938477 20.345703 18.691406 20.657227 18.691406 c
|
||||||
|
h
|
||||||
|
3.201172 18.691406 m
|
||||||
|
3.512695 18.691406 3.759766 18.938477 3.759766 19.228516 c
|
||||||
|
3.759766 19.540039 3.512695 19.797852 3.201172 19.797852 c
|
||||||
|
2.911133 19.797852 2.653320 19.540039 2.653320 19.228516 c
|
||||||
|
2.653320 18.938477 2.911133 18.691406 3.201172 18.691406 c
|
||||||
|
h
|
||||||
|
11.945312 4.307617 m
|
||||||
|
7.691406 4.307617 4.318359 7.680664 4.318359 11.934570 c
|
||||||
|
4.318359 16.156250 7.712891 19.550781 11.945312 19.550781 c
|
||||||
|
16.145508 19.550781 19.561523 16.134766 19.561523 11.934570 c
|
||||||
|
19.561523 7.702148 16.166992 4.307617 11.945312 4.307617 c
|
||||||
|
h
|
||||||
|
21.795898 17.058594 m
|
||||||
|
22.085938 17.058594 22.343750 17.305664 22.343750 17.606445 c
|
||||||
|
22.343750 17.896484 22.085938 18.165039 21.795898 18.165039 c
|
||||||
|
21.484375 18.165039 21.248047 17.896484 21.248047 17.606445 c
|
||||||
|
21.248047 17.305664 21.484375 17.058594 21.795898 17.058594 c
|
||||||
|
h
|
||||||
|
2.073242 17.058594 m
|
||||||
|
2.374023 17.058594 2.631836 17.305664 2.631836 17.606445 c
|
||||||
|
2.631836 17.896484 2.374023 18.165039 2.073242 18.165039 c
|
||||||
|
1.772461 18.165039 1.514648 17.896484 1.514648 17.606445 c
|
||||||
|
1.514648 17.305664 1.772461 17.058594 2.073242 17.058594 c
|
||||||
|
h
|
||||||
|
22.633789 15.253906 m
|
||||||
|
22.923828 15.253906 23.181641 15.500977 23.181641 15.801758 c
|
||||||
|
23.181641 16.102539 22.923828 16.371094 22.633789 16.371094 c
|
||||||
|
22.311523 16.371094 22.075195 16.102539 22.075195 15.801758 c
|
||||||
|
22.075195 15.500977 22.311523 15.253906 22.633789 15.253906 c
|
||||||
|
h
|
||||||
|
1.235352 15.253906 m
|
||||||
|
1.557617 15.253906 1.793945 15.500977 1.793945 15.801758 c
|
||||||
|
1.793945 16.102539 1.557617 16.371094 1.235352 16.371094 c
|
||||||
|
0.934570 16.371094 0.676758 16.102539 0.676758 15.801758 c
|
||||||
|
0.676758 15.500977 0.934570 15.253906 1.235352 15.253906 c
|
||||||
|
h
|
||||||
|
11.945312 7.498047 m
|
||||||
|
14.383789 7.498047 16.349609 9.463867 16.349609 11.913086 c
|
||||||
|
16.349609 14.351562 14.383789 16.317383 11.945312 16.317383 c
|
||||||
|
9.496094 16.317383 7.530273 14.351562 7.530273 11.913086 c
|
||||||
|
7.530273 9.453125 9.485352 7.498047 11.945312 7.498047 c
|
||||||
|
h
|
||||||
|
23.138672 13.341797 m
|
||||||
|
23.428711 13.341797 23.697266 13.599609 23.697266 13.900391 c
|
||||||
|
23.697266 14.190430 23.428711 14.458984 23.138672 14.458984 c
|
||||||
|
22.816406 14.458984 22.580078 14.190430 22.580078 13.900391 c
|
||||||
|
22.580078 13.599609 22.816406 13.341797 23.138672 13.341797 c
|
||||||
|
h
|
||||||
|
0.719727 13.341797 m
|
||||||
|
1.041992 13.341797 1.278320 13.599609 1.278320 13.900391 c
|
||||||
|
1.278320 14.190430 1.041992 14.458984 0.719727 14.458984 c
|
||||||
|
0.429688 14.458984 0.171875 14.190430 0.171875 13.900391 c
|
||||||
|
0.171875 13.599609 0.429688 13.341797 0.719727 13.341797 c
|
||||||
|
h
|
||||||
|
11.945312 9.517578 m
|
||||||
|
10.613281 9.517578 9.549805 10.581055 9.549805 11.913086 c
|
||||||
|
9.549805 13.223633 10.624023 14.297852 11.945312 14.297852 c
|
||||||
|
13.255859 14.297852 14.330078 13.212891 14.330078 11.913086 c
|
||||||
|
14.330078 10.591797 13.266602 9.517578 11.945312 9.517578 c
|
||||||
|
h
|
||||||
|
0.558594 11.375977 m
|
||||||
|
0.870117 11.375977 1.106445 11.633789 1.106445 11.913086 c
|
||||||
|
1.106445 12.224609 0.870117 12.482422 0.558594 12.482422 c
|
||||||
|
0.257812 12.482422 0.000000 12.224609 0.000000 11.913086 c
|
||||||
|
0.000000 11.633789 0.257812 11.375977 0.558594 11.375977 c
|
||||||
|
h
|
||||||
|
23.310547 11.375977 m
|
||||||
|
23.600586 11.375977 23.869141 11.633789 23.869141 11.913086 c
|
||||||
|
23.869141 12.224609 23.600586 12.482422 23.310547 12.482422 c
|
||||||
|
22.999023 12.482422 22.751953 12.224609 22.751953 11.913086 c
|
||||||
|
22.751953 11.633789 22.999023 11.375977 23.310547 11.375977 c
|
||||||
|
h
|
||||||
|
0.719727 9.399414 m
|
||||||
|
1.041992 9.399414 1.278320 9.667969 1.278320 9.968750 c
|
||||||
|
1.278320 10.258789 1.041992 10.516602 0.719727 10.516602 c
|
||||||
|
0.429688 10.516602 0.171875 10.258789 0.171875 9.968750 c
|
||||||
|
0.171875 9.667969 0.429688 9.399414 0.719727 9.399414 c
|
||||||
|
h
|
||||||
|
23.138672 9.399414 m
|
||||||
|
23.428711 9.399414 23.697266 9.667969 23.697266 9.968750 c
|
||||||
|
23.697266 10.258789 23.428711 10.516602 23.138672 10.516602 c
|
||||||
|
22.816406 10.516602 22.580078 10.258789 22.580078 9.968750 c
|
||||||
|
22.580078 9.667969 22.816406 9.399414 23.138672 9.399414 c
|
||||||
|
h
|
||||||
|
1.235352 7.498047 m
|
||||||
|
1.557617 7.498047 1.793945 7.755859 1.793945 8.067383 c
|
||||||
|
1.793945 8.346680 1.557617 8.615234 1.235352 8.615234 c
|
||||||
|
0.934570 8.615234 0.676758 8.346680 0.676758 8.067383 c
|
||||||
|
0.676758 7.755859 0.934570 7.498047 1.235352 7.498047 c
|
||||||
|
h
|
||||||
|
22.633789 7.498047 m
|
||||||
|
22.923828 7.498047 23.181641 7.755859 23.181641 8.067383 c
|
||||||
|
23.181641 8.346680 22.923828 8.615234 22.633789 8.615234 c
|
||||||
|
22.311523 8.615234 22.075195 8.346680 22.075195 8.067383 c
|
||||||
|
22.075195 7.755859 22.311523 7.498047 22.633789 7.498047 c
|
||||||
|
h
|
||||||
|
2.073242 5.693359 m
|
||||||
|
2.374023 5.693359 2.631836 5.961914 2.631836 6.262695 c
|
||||||
|
2.631836 6.563477 2.374023 6.810547 2.073242 6.810547 c
|
||||||
|
1.772461 6.810547 1.514648 6.563477 1.514648 6.262695 c
|
||||||
|
1.514648 5.961914 1.772461 5.693359 2.073242 5.693359 c
|
||||||
|
h
|
||||||
|
21.795898 5.693359 m
|
||||||
|
22.085938 5.693359 22.343750 5.961914 22.343750 6.262695 c
|
||||||
|
22.343750 6.563477 22.085938 6.810547 21.795898 6.810547 c
|
||||||
|
21.484375 6.810547 21.248047 6.563477 21.248047 6.262695 c
|
||||||
|
21.248047 5.961914 21.484375 5.693359 21.795898 5.693359 c
|
||||||
|
h
|
||||||
|
3.201172 4.071289 m
|
||||||
|
3.512695 4.071289 3.759766 4.329102 3.759766 4.629883 c
|
||||||
|
3.759766 4.930664 3.512695 5.177734 3.201172 5.177734 c
|
||||||
|
2.911133 5.177734 2.653320 4.930664 2.653320 4.629883 c
|
||||||
|
2.653320 4.329102 2.911133 4.071289 3.201172 4.071289 c
|
||||||
|
h
|
||||||
|
20.657227 4.071289 m
|
||||||
|
20.958008 4.071289 21.215820 4.329102 21.215820 4.629883 c
|
||||||
|
21.215820 4.930664 20.958008 5.177734 20.657227 5.177734 c
|
||||||
|
20.345703 5.177734 20.098633 4.930664 20.098633 4.629883 c
|
||||||
|
20.098633 4.329102 20.345703 4.071289 20.657227 4.071289 c
|
||||||
|
h
|
||||||
|
4.608398 2.664062 m
|
||||||
|
4.919922 2.664062 5.166992 2.921875 5.166992 3.233398 c
|
||||||
|
5.166992 3.523438 4.919922 3.770508 4.608398 3.770508 c
|
||||||
|
4.318359 3.770508 4.049805 3.523438 4.049805 3.233398 c
|
||||||
|
4.049805 2.921875 4.318359 2.664062 4.608398 2.664062 c
|
||||||
|
h
|
||||||
|
19.250000 2.664062 m
|
||||||
|
19.550781 2.664062 19.808594 2.921875 19.808594 3.233398 c
|
||||||
|
19.808594 3.523438 19.550781 3.770508 19.250000 3.770508 c
|
||||||
|
18.949219 3.770508 18.712891 3.523438 18.712891 3.233398 c
|
||||||
|
18.712891 2.921875 18.949219 2.664062 19.250000 2.664062 c
|
||||||
|
h
|
||||||
|
6.241211 1.525391 m
|
||||||
|
6.563477 1.525391 6.799805 1.793945 6.799805 2.094727 c
|
||||||
|
6.799805 2.384766 6.563477 2.642578 6.241211 2.642578 c
|
||||||
|
5.940430 2.642578 5.682617 2.384766 5.682617 2.094727 c
|
||||||
|
5.682617 1.793945 5.940430 1.525391 6.241211 1.525391 c
|
||||||
|
h
|
||||||
|
17.627930 1.525391 m
|
||||||
|
17.917969 1.525391 18.175781 1.793945 18.175781 2.094727 c
|
||||||
|
18.175781 2.384766 17.917969 2.642578 17.627930 2.642578 c
|
||||||
|
17.316406 2.642578 17.069336 2.384766 17.069336 2.094727 c
|
||||||
|
17.069336 1.793945 17.316406 1.525391 17.627930 1.525391 c
|
||||||
|
h
|
||||||
|
8.035156 0.676758 m
|
||||||
|
8.346680 0.676758 8.583008 0.945312 8.583008 1.246094 c
|
||||||
|
8.583008 1.546875 8.346680 1.793945 8.035156 1.793945 c
|
||||||
|
7.745117 1.793945 7.487305 1.546875 7.487305 1.246094 c
|
||||||
|
7.487305 0.945312 7.745117 0.676758 8.035156 0.676758 c
|
||||||
|
h
|
||||||
|
15.833984 0.676758 m
|
||||||
|
16.113281 0.676758 16.381836 0.945312 16.381836 1.246094 c
|
||||||
|
16.381836 1.546875 16.113281 1.793945 15.833984 1.793945 c
|
||||||
|
15.511719 1.793945 15.275391 1.546875 15.275391 1.246094 c
|
||||||
|
15.275391 0.945312 15.511719 0.676758 15.833984 0.676758 c
|
||||||
|
h
|
||||||
|
9.947266 0.171875 m
|
||||||
|
10.258789 0.171875 10.495117 0.440430 10.495117 0.741211 c
|
||||||
|
10.495117 1.031250 10.258789 1.278320 9.947266 1.278320 c
|
||||||
|
9.657227 1.278320 9.388672 1.031250 9.388672 0.741211 c
|
||||||
|
9.388672 0.440430 9.657227 0.171875 9.947266 0.171875 c
|
||||||
|
h
|
||||||
|
13.921875 0.171875 m
|
||||||
|
14.211914 0.171875 14.480469 0.440430 14.480469 0.741211 c
|
||||||
|
14.480469 1.031250 14.211914 1.278320 13.921875 1.278320 c
|
||||||
|
13.599609 1.278320 13.363281 1.031250 13.363281 0.741211 c
|
||||||
|
13.363281 0.440430 13.599609 0.171875 13.921875 0.171875 c
|
||||||
|
h
|
||||||
|
11.934570 0.000000 m
|
||||||
|
12.246094 0.000000 12.482422 0.257812 12.482422 0.569336 c
|
||||||
|
12.482422 0.848633 12.246094 1.106445 11.934570 1.106445 c
|
||||||
|
11.644531 1.106445 11.375977 0.848633 11.375977 0.569336 c
|
||||||
|
11.375977 0.257812 11.644531 0.000000 11.934570 0.000000 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
10544
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 36.000000 36.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
|
||||||
|
0000010634 00000 n
|
||||||
|
0000010658 00000 n
|
||||||
|
0000010831 00000 n
|
||||||
|
0000010905 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
10964
|
||||||
|
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Panorama.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Panorama.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "attach_pano.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
89
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Panorama.imageset/attach_pano.pdf
vendored
Normal file
89
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Panorama.imageset/attach_pano.pdf
vendored
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
%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 4.889648 8.539062 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
1.804688 0.000000 m
|
||||||
|
3.791992 0.000000 6.821289 2.363281 13.610352 2.363281 c
|
||||||
|
20.388672 2.363281 23.439453 0.010742 25.416016 0.010742 c
|
||||||
|
26.597656 0.010742 27.220703 0.730469 27.220703 1.922852 c
|
||||||
|
27.220703 16.478516 l
|
||||||
|
27.220703 17.681641 26.597656 18.401367 25.416016 18.401367 c
|
||||||
|
23.439453 18.401367 20.388672 16.038086 13.610352 16.038086 c
|
||||||
|
6.842773 16.038086 3.791992 18.401367 1.804688 18.401367 c
|
||||||
|
0.623047 18.401367 0.000000 17.681641 0.000000 16.489258 c
|
||||||
|
0.000000 1.912109 l
|
||||||
|
0.000000 0.719727 0.623047 0.000000 1.804688 0.000000 c
|
||||||
|
h
|
||||||
|
2.030273 1.783203 m
|
||||||
|
1.836914 1.783203 1.729492 1.890625 1.729492 2.094727 c
|
||||||
|
1.729492 16.306641 l
|
||||||
|
1.729492 16.510742 1.836914 16.618164 2.030273 16.618164 c
|
||||||
|
3.083008 16.618164 6.778320 14.405273 13.610352 14.405273 c
|
||||||
|
20.442383 14.405273 24.374023 16.628906 25.201172 16.628906 c
|
||||||
|
25.383789 16.628906 25.491211 16.521484 25.491211 16.306641 c
|
||||||
|
25.491211 2.094727 l
|
||||||
|
25.491211 1.890625 25.383789 1.783203 25.201172 1.783203 c
|
||||||
|
24.148438 1.783203 20.442383 3.996094 13.610352 3.996094 c
|
||||||
|
6.756836 3.996094 2.857422 1.783203 2.030273 1.783203 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
1200
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 36.000000 36.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
|
||||||
|
0000001290 00000 n
|
||||||
|
0000001313 00000 n
|
||||||
|
0000001486 00000 n
|
||||||
|
0000001560 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
1619
|
||||||
|
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Portrait.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Portrait.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "attach_portrait.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
100
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Portrait.imageset/attach_portrait.pdf
vendored
Normal file
100
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Portrait.imageset/attach_portrait.pdf
vendored
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
%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 7.150391 5.654785 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
1.503906 5.322754 m
|
||||||
|
9.958008 0.531738 l
|
||||||
|
10.559570 0.187988 11.128906 0.187988 11.741211 0.531738 c
|
||||||
|
20.184570 5.322754 l
|
||||||
|
21.172852 5.881348 21.688477 6.450684 21.688477 7.986816 c
|
||||||
|
21.688477 16.494629 l
|
||||||
|
21.688477 17.611816 21.280273 18.310059 20.377930 18.825684 c
|
||||||
|
12.772461 23.144043 l
|
||||||
|
11.472656 23.895996 10.215820 23.895996 8.916016 23.144043 c
|
||||||
|
1.321289 18.825684 l
|
||||||
|
0.408203 18.310059 0.000000 17.611816 0.000000 16.494629 c
|
||||||
|
0.000000 7.986816 l
|
||||||
|
0.000000 6.450684 0.526367 5.881348 1.503906 5.322754 c
|
||||||
|
h
|
||||||
|
10.849609 12.874512 m
|
||||||
|
2.556641 17.568848 l
|
||||||
|
9.635742 21.607910 l
|
||||||
|
10.462891 22.080566 11.225586 22.091309 12.063477 21.607910 c
|
||||||
|
19.142578 17.568848 l
|
||||||
|
10.849609 12.874512 l
|
||||||
|
h
|
||||||
|
2.470703 6.740723 m
|
||||||
|
1.847656 7.084473 1.632812 7.449707 1.632812 8.040527 c
|
||||||
|
1.632812 16.150879 l
|
||||||
|
10.000977 11.370605 l
|
||||||
|
10.000977 2.454590 l
|
||||||
|
2.470703 6.740723 l
|
||||||
|
h
|
||||||
|
19.228516 6.740723 m
|
||||||
|
11.687500 2.454590 l
|
||||||
|
11.687500 11.370605 l
|
||||||
|
20.055664 16.150879 l
|
||||||
|
20.055664 8.040527 l
|
||||||
|
20.055664 7.449707 19.840820 7.084473 19.228516 6.740723 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
1132
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 36.000000 36.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
|
||||||
|
0000001222 00000 n
|
||||||
|
0000001245 00000 n
|
||||||
|
0000001418 00000 n
|
||||||
|
0000001492 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
1551
|
||||||
|
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/ScreenRecording.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/ScreenRecording.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "attach_screenrec.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
%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 7.042969 6.798828 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
10.957031 0.000000 m
|
||||||
|
16.951172 0.000000 21.914062 4.973633 21.914062 10.957031 c
|
||||||
|
21.914062 16.951172 16.940430 21.914062 10.946289 21.914062 c
|
||||||
|
4.962891 21.914062 0.000000 16.951172 0.000000 10.957031 c
|
||||||
|
0.000000 4.973633 4.973633 0.000000 10.957031 0.000000 c
|
||||||
|
h
|
||||||
|
10.957031 1.826172 m
|
||||||
|
5.886719 1.826172 1.836914 5.886719 1.836914 10.957031 c
|
||||||
|
1.836914 16.027344 5.875977 20.087891 10.946289 20.087891 c
|
||||||
|
16.016602 20.087891 20.077148 16.027344 20.087891 10.957031 c
|
||||||
|
20.098633 5.886719 16.027344 1.826172 10.957031 1.826172 c
|
||||||
|
h
|
||||||
|
10.967773 6.756836 m
|
||||||
|
13.288086 6.756836 15.178711 8.647461 15.178711 10.978516 c
|
||||||
|
15.178711 13.298828 13.288086 15.178711 10.967773 15.178711 c
|
||||||
|
8.636719 15.178711 6.746094 13.298828 6.746094 10.978516 c
|
||||||
|
6.746094 8.647461 8.636719 6.756836 10.967773 6.756836 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
909
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 36.000000 36.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
|
||||||
|
0000000999 00000 n
|
||||||
|
0000001021 00000 n
|
||||||
|
0000001194 00000 n
|
||||||
|
0000001268 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
1327
|
||||||
|
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Screenshot.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Screenshot.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "attach_screen.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
113
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Screenshot.imageset/attach_screen.pdf
vendored
Normal file
113
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Screenshot.imageset/attach_screen.pdf
vendored
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
%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 7.983398 7.228516 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
0.859375 14.190430 m
|
||||||
|
1.428711 14.190430 1.729492 14.512695 1.729492 15.071289 c
|
||||||
|
1.729492 17.606445 l
|
||||||
|
1.729492 18.723633 2.320312 19.292969 3.394531 19.292969 c
|
||||||
|
5.994141 19.292969 l
|
||||||
|
6.563477 19.292969 6.875000 19.604492 6.875000 20.163086 c
|
||||||
|
6.875000 20.721680 6.563477 21.022461 5.994141 21.022461 c
|
||||||
|
3.373047 21.022461 l
|
||||||
|
1.127930 21.022461 0.000000 19.916016 0.000000 17.703125 c
|
||||||
|
0.000000 15.071289 l
|
||||||
|
0.000000 14.512695 0.311523 14.190430 0.859375 14.190430 c
|
||||||
|
h
|
||||||
|
20.163086 14.190430 m
|
||||||
|
20.732422 14.190430 21.033203 14.512695 21.033203 15.071289 c
|
||||||
|
21.033203 17.703125 l
|
||||||
|
21.033203 19.916016 19.905273 21.022461 17.660156 21.022461 c
|
||||||
|
15.028320 21.022461 l
|
||||||
|
14.469727 21.022461 14.158203 20.721680 14.158203 20.163086 c
|
||||||
|
14.158203 19.604492 14.469727 19.292969 15.028320 19.292969 c
|
||||||
|
17.627930 19.292969 l
|
||||||
|
18.691406 19.292969 19.303711 18.723633 19.303711 17.606445 c
|
||||||
|
19.303711 15.071289 l
|
||||||
|
19.303711 14.512695 19.615234 14.190430 20.163086 14.190430 c
|
||||||
|
h
|
||||||
|
3.373047 0.000000 m
|
||||||
|
5.994141 0.000000 l
|
||||||
|
6.563477 0.000000 6.875000 0.311523 6.875000 0.859375 c
|
||||||
|
6.875000 1.417969 6.563477 1.729492 5.994141 1.729492 c
|
||||||
|
3.394531 1.729492 l
|
||||||
|
2.320312 1.729492 1.729492 2.298828 1.729492 3.416016 c
|
||||||
|
1.729492 5.951172 l
|
||||||
|
1.729492 6.520508 1.417969 6.832031 0.859375 6.832031 c
|
||||||
|
0.300781 6.832031 0.000000 6.520508 0.000000 5.951172 c
|
||||||
|
0.000000 3.330078 l
|
||||||
|
0.000000 1.106445 1.127930 0.000000 3.373047 0.000000 c
|
||||||
|
h
|
||||||
|
15.028320 0.000000 m
|
||||||
|
17.660156 0.000000 l
|
||||||
|
19.905273 0.000000 21.033203 1.117188 21.033203 3.330078 c
|
||||||
|
21.033203 5.951172 l
|
||||||
|
21.033203 6.520508 20.721680 6.832031 20.163086 6.832031 c
|
||||||
|
19.604492 6.832031 19.303711 6.520508 19.303711 5.951172 c
|
||||||
|
19.303711 3.416016 l
|
||||||
|
19.303711 2.298828 18.691406 1.729492 17.627930 1.729492 c
|
||||||
|
15.028320 1.729492 l
|
||||||
|
14.469727 1.729492 14.158203 1.417969 14.158203 0.859375 c
|
||||||
|
14.158203 0.311523 14.469727 0.000000 15.028320 0.000000 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
1970
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 36.000000 36.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
|
||||||
|
0000002060 00000 n
|
||||||
|
0000002083 00000 n
|
||||||
|
0000002256 00000 n
|
||||||
|
0000002330 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
2389
|
||||||
|
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Selfie.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Selfie.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "attach_selfie.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
92
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Selfie.imageset/attach_selfie.pdf
vendored
Normal file
92
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Selfie.imageset/attach_selfie.pdf
vendored
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
%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 8.106445 7.851562 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
3.373047 0.000000 m
|
||||||
|
16.403320 0.000000 l
|
||||||
|
18.659180 0.000000 19.776367 1.117188 19.776367 3.330078 c
|
||||||
|
19.776367 16.446289 l
|
||||||
|
19.776367 18.659180 18.659180 19.776367 16.403320 19.776367 c
|
||||||
|
3.373047 19.776367 l
|
||||||
|
1.127930 19.776367 0.000000 18.669922 0.000000 16.446289 c
|
||||||
|
0.000000 3.330078 l
|
||||||
|
0.000000 1.106445 1.127930 0.000000 3.373047 0.000000 c
|
||||||
|
h
|
||||||
|
1.729492 3.416016 m
|
||||||
|
1.729492 16.360352 l
|
||||||
|
1.729492 17.477539 2.320312 18.046875 3.394531 18.046875 c
|
||||||
|
16.381836 18.046875 l
|
||||||
|
17.445312 18.046875 18.046875 17.477539 18.046875 16.360352 c
|
||||||
|
18.046875 3.416016 l
|
||||||
|
18.046875 2.578125 17.703125 2.051758 17.080078 1.836914 c
|
||||||
|
16.156250 4.468750 13.320312 6.305664 9.904297 6.305664 c
|
||||||
|
6.477539 6.305664 3.641602 4.458008 2.707031 1.826172 c
|
||||||
|
2.073242 2.041016 1.729492 2.567383 1.729492 3.416016 c
|
||||||
|
h
|
||||||
|
9.893555 8.099609 m
|
||||||
|
11.945312 8.078125 13.567383 9.829102 13.567383 12.127930 c
|
||||||
|
13.567383 14.287109 11.945312 16.070312 9.893555 16.070312 c
|
||||||
|
7.841797 16.070312 6.208984 14.287109 6.219727 12.127930 c
|
||||||
|
6.230469 9.829102 7.841797 8.121094 9.893555 8.099609 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
1162
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 36.000000 36.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
|
||||||
|
0000001252 00000 n
|
||||||
|
0000001275 00000 n
|
||||||
|
0000001448 00000 n
|
||||||
|
0000001522 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
1581
|
||||||
|
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/SloMo.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/SloMo.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "attach_slowmo.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
161
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/SloMo.imageset/attach_slowmo.pdf
vendored
Normal file
161
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/SloMo.imageset/attach_slowmo.pdf
vendored
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
%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 6.382812 5.627930 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
12.106445 24.223633 m
|
||||||
|
11.676758 24.223633 11.343750 23.879883 11.343750 23.450195 c
|
||||||
|
11.343750 19.636719 l
|
||||||
|
11.343750 19.207031 11.676758 18.863281 12.106445 18.863281 c
|
||||||
|
12.546875 18.863281 12.879883 19.207031 12.879883 19.636719 c
|
||||||
|
12.879883 23.450195 l
|
||||||
|
12.879883 23.879883 12.546875 24.223633 12.106445 24.223633 c
|
||||||
|
h
|
||||||
|
6.058594 22.612305 m
|
||||||
|
5.671875 22.386719 5.564453 21.924805 5.779297 21.548828 c
|
||||||
|
7.680664 18.240234 l
|
||||||
|
7.906250 17.864258 8.357422 17.735352 8.733398 17.960938 c
|
||||||
|
9.120117 18.175781 9.227539 18.637695 9.023438 19.002930 c
|
||||||
|
7.111328 22.322266 l
|
||||||
|
6.885742 22.687500 6.434570 22.816406 6.058594 22.612305 c
|
||||||
|
h
|
||||||
|
18.175781 22.601562 m
|
||||||
|
17.789062 22.816406 17.337891 22.687500 17.112305 22.322266 c
|
||||||
|
15.210938 19.002930 l
|
||||||
|
14.996094 18.637695 15.103516 18.175781 15.490234 17.950195 c
|
||||||
|
15.866211 17.746094 16.317383 17.864258 16.542969 18.240234 c
|
||||||
|
18.455078 21.548828 l
|
||||||
|
18.659180 21.924805 18.551758 22.386719 18.175781 22.601562 c
|
||||||
|
h
|
||||||
|
1.632812 18.175781 m
|
||||||
|
1.407227 17.789062 1.536133 17.337891 1.912109 17.112305 c
|
||||||
|
5.220703 15.200195 l
|
||||||
|
5.596680 14.996094 6.047852 15.103516 6.273438 15.479492 c
|
||||||
|
6.477539 15.866211 6.359375 16.317383 5.983398 16.542969 c
|
||||||
|
2.674805 18.455078 l
|
||||||
|
2.298828 18.659180 1.836914 18.551758 1.632812 18.175781 c
|
||||||
|
h
|
||||||
|
22.612305 18.165039 m
|
||||||
|
22.386719 18.551758 21.924805 18.659180 21.548828 18.455078 c
|
||||||
|
18.240234 16.542969 l
|
||||||
|
17.864258 16.317383 17.735352 15.866211 17.971680 15.479492 c
|
||||||
|
18.175781 15.114258 18.637695 14.996094 19.002930 15.200195 c
|
||||||
|
22.322266 17.112305 l
|
||||||
|
22.687500 17.337891 22.816406 17.789062 22.612305 18.165039 c
|
||||||
|
h
|
||||||
|
24.223633 12.117188 m
|
||||||
|
24.223633 12.546875 23.890625 12.879883 23.450195 12.879883 c
|
||||||
|
19.636719 12.879883 l
|
||||||
|
19.207031 12.879883 18.863281 12.546875 18.863281 12.117188 c
|
||||||
|
18.863281 11.676758 19.207031 11.343750 19.636719 11.343750 c
|
||||||
|
23.450195 11.343750 l
|
||||||
|
23.890625 11.343750 24.223633 11.676758 24.223633 12.117188 c
|
||||||
|
h
|
||||||
|
0.000000 12.117188 m
|
||||||
|
0.000000 11.676758 0.343750 11.343750 0.773438 11.343750 c
|
||||||
|
4.586914 11.343750 l
|
||||||
|
5.027344 11.343750 5.360352 11.676758 5.360352 12.117188 c
|
||||||
|
5.360352 12.546875 5.027344 12.879883 4.586914 12.879883 c
|
||||||
|
0.773438 12.879883 l
|
||||||
|
0.343750 12.879883 0.000000 12.546875 0.000000 12.117188 c
|
||||||
|
h
|
||||||
|
22.601562 6.058594 m
|
||||||
|
22.827148 6.434570 22.687500 6.885742 22.322266 7.111328 c
|
||||||
|
19.002930 9.023438 l
|
||||||
|
18.637695 9.227539 18.175781 9.120117 17.960938 8.744141 c
|
||||||
|
17.746094 8.357422 17.864258 7.906250 18.240234 7.680664 c
|
||||||
|
21.548828 5.768555 l
|
||||||
|
21.924805 5.564453 22.386719 5.671875 22.601562 6.058594 c
|
||||||
|
h
|
||||||
|
1.632812 6.058594 m
|
||||||
|
1.836914 5.671875 2.298828 5.564453 2.674805 5.768555 c
|
||||||
|
5.983398 7.680664 l
|
||||||
|
6.359375 7.906250 6.488281 8.357422 6.273438 8.733398 c
|
||||||
|
6.047852 9.120117 5.596680 9.227539 5.220703 9.023438 c
|
||||||
|
1.912109 7.111328 l
|
||||||
|
1.536133 6.885742 1.407227 6.434570 1.632812 6.058594 c
|
||||||
|
h
|
||||||
|
18.165039 1.622070 m
|
||||||
|
18.551758 1.836914 18.659180 2.298828 18.455078 2.674805 c
|
||||||
|
16.542969 5.983398 l
|
||||||
|
16.328125 6.359375 15.866211 6.488281 15.490234 6.273438 c
|
||||||
|
15.103516 6.047852 14.996094 5.596680 15.210938 5.220703 c
|
||||||
|
17.112305 1.912109 l
|
||||||
|
17.337891 1.536133 17.789062 1.407227 18.165039 1.622070 c
|
||||||
|
h
|
||||||
|
6.058594 1.622070 m
|
||||||
|
6.434570 1.407227 6.885742 1.536133 7.111328 1.912109 c
|
||||||
|
9.023438 5.220703 l
|
||||||
|
9.227539 5.596680 9.120117 6.047852 8.744141 6.262695 c
|
||||||
|
8.357422 6.477539 7.906250 6.359375 7.680664 5.983398 c
|
||||||
|
5.779297 2.674805 l
|
||||||
|
5.564453 2.298828 5.671875 1.836914 6.058594 1.622070 c
|
||||||
|
h
|
||||||
|
12.106445 0.000000 m
|
||||||
|
12.546875 0.000000 12.879883 0.343750 12.879883 0.773438 c
|
||||||
|
12.879883 4.586914 l
|
||||||
|
12.879883 5.016602 12.546875 5.360352 12.106445 5.360352 c
|
||||||
|
11.676758 5.360352 11.343750 5.016602 11.343750 4.586914 c
|
||||||
|
11.343750 0.773438 l
|
||||||
|
11.343750 0.343750 11.676758 0.000000 12.106445 0.000000 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
3768
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 36.000000 36.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
|
||||||
|
0000003858 00000 n
|
||||||
|
0000003881 00000 n
|
||||||
|
0000004054 00000 n
|
||||||
|
0000004128 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
4187
|
||||||
|
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Timelapse.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Timelapse.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "attach_timelapse.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
257
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Timelapse.imageset/attach_timelapse.pdf
vendored
Normal file
257
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Timelapse.imageset/attach_timelapse.pdf
vendored
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
%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 6.382812 5.627930 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
12.106445 24.223633 m
|
||||||
|
11.751953 24.223633 11.472656 23.933594 11.472656 23.579102 c
|
||||||
|
11.472656 19.593750 l
|
||||||
|
11.472656 19.228516 11.751953 18.949219 12.106445 18.949219 c
|
||||||
|
12.471680 18.949219 12.750977 19.228516 12.750977 19.593750 c
|
||||||
|
12.750977 23.579102 l
|
||||||
|
12.750977 23.933594 12.471680 24.223633 12.106445 24.223633 c
|
||||||
|
h
|
||||||
|
8.937500 23.933594 m
|
||||||
|
8.583008 23.858398 8.389648 23.546875 8.497070 23.138672 c
|
||||||
|
8.851562 21.785156 l
|
||||||
|
8.948242 21.452148 9.281250 21.269531 9.678711 21.387695 c
|
||||||
|
10.054688 21.505859 10.205078 21.806641 10.097656 22.150391 c
|
||||||
|
9.721680 23.450195 l
|
||||||
|
9.614258 23.836914 9.302734 23.998047 8.937500 23.933594 c
|
||||||
|
h
|
||||||
|
15.286133 23.901367 m
|
||||||
|
14.942383 24.019531 14.609375 23.847656 14.501953 23.450195 c
|
||||||
|
14.136719 22.128906 l
|
||||||
|
14.040039 21.785156 14.233398 21.430664 14.577148 21.344727 c
|
||||||
|
14.920898 21.258789 15.264648 21.441406 15.361328 21.795898 c
|
||||||
|
15.715820 23.117188 l
|
||||||
|
15.812500 23.482422 15.629883 23.804688 15.286133 23.901367 c
|
||||||
|
h
|
||||||
|
6.058594 22.612305 m
|
||||||
|
5.747070 22.429688 5.650391 22.042969 5.833008 21.731445 c
|
||||||
|
7.820312 18.272461 l
|
||||||
|
8.002930 17.950195 8.389648 17.853516 8.690430 18.036133 c
|
||||||
|
9.001953 18.208008 9.109375 18.594727 8.926758 18.906250 c
|
||||||
|
6.928711 22.375977 l
|
||||||
|
6.746094 22.676758 6.370117 22.773438 6.058594 22.612305 c
|
||||||
|
h
|
||||||
|
18.175781 22.601562 m
|
||||||
|
17.864258 22.773438 17.477539 22.676758 17.294922 22.375977 c
|
||||||
|
15.307617 18.906250 l
|
||||||
|
15.114258 18.594727 15.221680 18.208008 15.533203 18.036133 c
|
||||||
|
15.833984 17.853516 16.231445 17.950195 16.403320 18.272461 c
|
||||||
|
18.401367 21.731445 l
|
||||||
|
18.573242 22.042969 18.476562 22.418945 18.175781 22.601562 c
|
||||||
|
h
|
||||||
|
3.458984 20.753906 m
|
||||||
|
3.201172 20.506836 3.233398 20.098633 3.469727 19.851562 c
|
||||||
|
4.425781 18.884766 l
|
||||||
|
4.694336 18.616211 5.059570 18.605469 5.338867 18.874023 c
|
||||||
|
5.585938 19.121094 5.596680 19.507812 5.328125 19.787109 c
|
||||||
|
4.372070 20.743164 l
|
||||||
|
4.092773 21.022461 3.727539 21.011719 3.458984 20.753906 c
|
||||||
|
h
|
||||||
|
20.764648 20.743164 m
|
||||||
|
20.506836 21.000977 20.098633 20.979492 19.862305 20.743164 c
|
||||||
|
18.884766 19.776367 l
|
||||||
|
18.616211 19.497070 18.616211 19.131836 18.884766 18.874023 c
|
||||||
|
19.142578 18.605469 19.529297 18.605469 19.776367 18.863281 c
|
||||||
|
20.732422 19.830078 l
|
||||||
|
21.000977 20.109375 21.011719 20.485352 20.764648 20.743164 c
|
||||||
|
h
|
||||||
|
1.632812 18.175781 m
|
||||||
|
1.450195 17.864258 1.546875 17.477539 1.858398 17.294922 c
|
||||||
|
5.317383 15.296875 l
|
||||||
|
5.639648 15.114258 6.015625 15.221680 6.198242 15.522461 c
|
||||||
|
6.370117 15.833984 6.273438 16.220703 5.951172 16.403320 c
|
||||||
|
2.492188 18.401367 l
|
||||||
|
2.180664 18.573242 1.804688 18.476562 1.632812 18.175781 c
|
||||||
|
h
|
||||||
|
22.612305 18.165039 m
|
||||||
|
22.429688 18.476562 22.042969 18.573242 21.731445 18.401367 c
|
||||||
|
18.272461 16.403320 l
|
||||||
|
17.950195 16.220703 17.853516 15.833984 18.036133 15.522461 c
|
||||||
|
18.208008 15.221680 18.594727 15.114258 18.906250 15.296875 c
|
||||||
|
22.375977 17.294922 l
|
||||||
|
22.676758 17.477539 22.773438 17.853516 22.612305 18.165039 c
|
||||||
|
h
|
||||||
|
23.922852 15.264648 m
|
||||||
|
23.836914 15.619141 23.471680 15.823242 23.149414 15.726562 c
|
||||||
|
21.806641 15.361328 l
|
||||||
|
21.462891 15.264648 21.258789 14.931641 21.376953 14.534180 c
|
||||||
|
21.462891 14.254883 21.763672 14.029297 22.150391 14.125977 c
|
||||||
|
23.450195 14.491211 l
|
||||||
|
23.826172 14.587891 24.008789 14.931641 23.922852 15.264648 c
|
||||||
|
h
|
||||||
|
0.290039 15.275391 m
|
||||||
|
0.214844 14.931641 0.429688 14.587891 0.751953 14.491211 c
|
||||||
|
2.073242 14.115234 l
|
||||||
|
2.438477 14.029297 2.782227 14.222656 2.857422 14.577148 c
|
||||||
|
2.932617 14.920898 2.771484 15.286133 2.416992 15.372070 c
|
||||||
|
1.095703 15.705078 l
|
||||||
|
0.708984 15.801758 0.365234 15.608398 0.290039 15.275391 c
|
||||||
|
h
|
||||||
|
24.223633 12.117188 m
|
||||||
|
24.223633 12.471680 23.944336 12.750977 23.579102 12.750977 c
|
||||||
|
19.593750 12.750977 l
|
||||||
|
19.228516 12.750977 18.949219 12.471680 18.949219 12.117188 c
|
||||||
|
18.949219 11.751953 19.228516 11.472656 19.593750 11.472656 c
|
||||||
|
23.579102 11.472656 l
|
||||||
|
23.944336 11.472656 24.223633 11.751953 24.223633 12.117188 c
|
||||||
|
h
|
||||||
|
0.000000 12.117188 m
|
||||||
|
0.000000 11.751953 0.290039 11.472656 0.644531 11.472656 c
|
||||||
|
4.629883 11.472656 l
|
||||||
|
5.005859 11.472656 5.274414 11.751953 5.274414 12.117188 c
|
||||||
|
5.274414 12.471680 5.005859 12.750977 4.629883 12.750977 c
|
||||||
|
0.644531 12.750977 l
|
||||||
|
0.290039 12.750977 0.000000 12.471680 0.000000 12.117188 c
|
||||||
|
h
|
||||||
|
23.922852 8.916016 m
|
||||||
|
24.019531 9.281250 23.858398 9.614258 23.482422 9.721680 c
|
||||||
|
22.150391 10.097656 l
|
||||||
|
21.785156 10.194336 21.452148 9.990234 21.366211 9.646484 c
|
||||||
|
21.280273 9.291992 21.473633 8.926758 21.806641 8.840820 c
|
||||||
|
23.127930 8.497070 l
|
||||||
|
23.503906 8.400391 23.826172 8.593750 23.922852 8.916016 c
|
||||||
|
h
|
||||||
|
0.300781 8.948242 m
|
||||||
|
0.386719 8.604492 0.751953 8.421875 1.084961 8.497070 c
|
||||||
|
2.416992 8.830078 l
|
||||||
|
2.782227 8.926758 2.964844 9.259766 2.868164 9.614258 c
|
||||||
|
2.771484 9.958008 2.427734 10.162109 2.073242 10.076172 c
|
||||||
|
0.784180 9.721680 l
|
||||||
|
0.386719 9.614258 0.214844 9.281250 0.300781 8.948242 c
|
||||||
|
h
|
||||||
|
22.601562 6.058594 m
|
||||||
|
22.773438 6.359375 22.676758 6.746094 22.375977 6.928711 c
|
||||||
|
18.906250 8.926758 l
|
||||||
|
18.594727 9.109375 18.208008 9.001953 18.036133 8.701172 c
|
||||||
|
17.853516 8.389648 17.950195 8.002930 18.272461 7.820312 c
|
||||||
|
21.731445 5.822266 l
|
||||||
|
22.042969 5.650391 22.418945 5.747070 22.601562 6.058594 c
|
||||||
|
h
|
||||||
|
1.622070 6.058594 m
|
||||||
|
1.793945 5.747070 2.180664 5.650391 2.492188 5.822266 c
|
||||||
|
5.951172 7.820312 l
|
||||||
|
6.273438 8.002930 6.370117 8.389648 6.198242 8.690430 c
|
||||||
|
6.015625 9.001953 5.639648 9.109375 5.317383 8.926758 c
|
||||||
|
1.858398 6.928711 l
|
||||||
|
1.546875 6.746094 1.450195 6.370117 1.622070 6.058594 c
|
||||||
|
h
|
||||||
|
6.058594 1.622070 m
|
||||||
|
6.359375 1.450195 6.756836 1.546875 6.928711 1.858398 c
|
||||||
|
8.926758 5.317383 l
|
||||||
|
9.109375 5.628906 9.001953 6.015625 8.701172 6.198242 c
|
||||||
|
8.389648 6.370117 8.002930 6.273438 7.820312 5.951172 c
|
||||||
|
5.833008 2.492188 l
|
||||||
|
5.650391 2.180664 5.747070 1.804688 6.058594 1.622070 c
|
||||||
|
h
|
||||||
|
18.165039 1.622070 m
|
||||||
|
18.476562 1.793945 18.573242 2.180664 18.401367 2.492188 c
|
||||||
|
16.403320 5.951172 l
|
||||||
|
16.231445 6.273438 15.833984 6.370117 15.533203 6.198242 c
|
||||||
|
15.221680 6.015625 15.114258 5.628906 15.307617 5.317383 c
|
||||||
|
17.294922 1.858398 l
|
||||||
|
17.477539 1.546875 17.853516 1.450195 18.165039 1.622070 c
|
||||||
|
h
|
||||||
|
20.753906 3.458984 m
|
||||||
|
21.022461 3.727539 21.000977 4.135742 20.775391 4.372070 c
|
||||||
|
19.787109 5.338867 l
|
||||||
|
19.529297 5.585938 19.142578 5.618164 18.863281 5.338867 c
|
||||||
|
18.616211 5.070312 18.637695 4.705078 18.884766 4.447266 c
|
||||||
|
19.851562 3.480469 l
|
||||||
|
20.120117 3.211914 20.496094 3.201172 20.753906 3.458984 c
|
||||||
|
h
|
||||||
|
3.469727 3.469727 m
|
||||||
|
3.738281 3.211914 4.125000 3.211914 4.361328 3.448242 c
|
||||||
|
5.338867 4.415039 l
|
||||||
|
5.607422 4.694336 5.618164 5.059570 5.349609 5.317383 c
|
||||||
|
5.102539 5.575195 4.694336 5.585938 4.447266 5.328125 c
|
||||||
|
3.491211 4.361328 l
|
||||||
|
3.222656 4.082031 3.211914 3.727539 3.469727 3.469727 c
|
||||||
|
h
|
||||||
|
12.106445 0.000000 m
|
||||||
|
12.471680 0.000000 12.750977 0.290039 12.750977 0.644531 c
|
||||||
|
12.750977 4.629883 l
|
||||||
|
12.750977 4.995117 12.471680 5.274414 12.106445 5.274414 c
|
||||||
|
11.751953 5.274414 11.472656 4.995117 11.472656 4.629883 c
|
||||||
|
11.472656 0.644531 l
|
||||||
|
11.472656 0.290039 11.751953 0.000000 12.106445 0.000000 c
|
||||||
|
h
|
||||||
|
15.286133 0.290039 m
|
||||||
|
15.694336 0.386719 15.812500 0.741211 15.726562 1.074219 c
|
||||||
|
15.382812 2.427734 l
|
||||||
|
15.286133 2.771484 14.920898 2.964844 14.577148 2.868164 c
|
||||||
|
14.201172 2.760742 14.040039 2.406250 14.136719 2.083984 c
|
||||||
|
14.523438 0.773438 l
|
||||||
|
14.630859 0.418945 14.899414 0.214844 15.286133 0.290039 c
|
||||||
|
h
|
||||||
|
8.883789 0.300781 m
|
||||||
|
9.281250 0.171875 9.635742 0.408203 9.721680 0.741211 c
|
||||||
|
10.086914 2.062500 l
|
||||||
|
10.183594 2.406250 9.990234 2.760742 9.646484 2.846680 c
|
||||||
|
9.302734 2.932617 8.958984 2.750000 8.862305 2.395508 c
|
||||||
|
8.507812 1.074219 l
|
||||||
|
8.411133 0.708984 8.529297 0.408203 8.883789 0.300781 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
7389
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 36.000000 36.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
|
||||||
|
0000007479 00000 n
|
||||||
|
0000007502 00000 n
|
||||||
|
0000007675 00000 n
|
||||||
|
0000007749 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
7808
|
||||||
|
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Video.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Video.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "attach_video.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
103
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Video.imageset/attach_video.pdf
vendored
Normal file
103
submodules/TelegramUI/Images.xcassets/Chat/Attach Menu/Video.imageset/attach_video.pdf
vendored
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
%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 5.592773 8.925781 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
4.189453 0.000000 m
|
||||||
|
15.415039 0.000000 l
|
||||||
|
18.036133 0.000000 19.604492 1.525391 19.604492 4.146484 c
|
||||||
|
19.604492 5.618164 l
|
||||||
|
23.665039 2.180664 l
|
||||||
|
24.094727 1.826172 24.567383 1.579102 25.007812 1.579102 c
|
||||||
|
25.953125 1.579102 26.576172 2.277344 26.576172 3.276367 c
|
||||||
|
26.576172 14.383789 l
|
||||||
|
26.576172 15.382812 25.953125 16.081055 25.007812 16.081055 c
|
||||||
|
24.567383 16.081055 24.094727 15.833984 23.665039 15.479492 c
|
||||||
|
19.604492 12.041992 l
|
||||||
|
19.604492 13.524414 l
|
||||||
|
19.604492 16.134766 18.036133 17.660156 15.415039 17.660156 c
|
||||||
|
4.189453 17.660156 l
|
||||||
|
1.686523 17.660156 0.000000 16.134766 0.000000 13.524414 c
|
||||||
|
0.000000 4.146484 l
|
||||||
|
0.000000 1.525391 1.568359 0.000000 4.189453 0.000000 c
|
||||||
|
h
|
||||||
|
4.490234 1.622070 m
|
||||||
|
2.728516 1.622070 1.729492 2.535156 1.729492 4.393555 c
|
||||||
|
1.729492 13.266602 l
|
||||||
|
1.729492 15.135742 2.728516 16.048828 4.490234 16.048828 c
|
||||||
|
15.114258 16.048828 l
|
||||||
|
16.865234 16.048828 17.875000 15.135742 17.875000 13.266602 c
|
||||||
|
17.875000 4.393555 l
|
||||||
|
17.875000 2.535156 16.865234 1.622070 15.114258 1.622070 c
|
||||||
|
4.490234 1.622070 l
|
||||||
|
h
|
||||||
|
24.470703 3.641602 m
|
||||||
|
19.604492 7.659180 l
|
||||||
|
19.604492 10.000977 l
|
||||||
|
24.470703 14.018555 l
|
||||||
|
24.567383 14.093750 24.631836 14.147461 24.728516 14.147461 c
|
||||||
|
24.857422 14.147461 24.911133 14.040039 24.911133 13.889648 c
|
||||||
|
24.911133 3.770508 l
|
||||||
|
24.911133 3.620117 24.857422 3.523438 24.728516 3.523438 c
|
||||||
|
24.631836 3.523438 24.567383 3.577148 24.470703 3.641602 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
1489
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 36.000000 36.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
|
||||||
|
0000001579 00000 n
|
||||||
|
0000001602 00000 n
|
||||||
|
0000001775 00000 n
|
||||||
|
0000001849 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
1908
|
||||||
|
%%EOF
|
@ -1,16 +1,8 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"filename" : "target_24.pdf",
|
||||||
"scale" : "1x"
|
"idiom" : "universal"
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
131
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/ReportPersonal.imageset/target_24.pdf
vendored
Normal file
131
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/ReportPersonal.imageset/target_24.pdf
vendored
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
%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 1.868011 1.601807 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
9.467012 16.798109 m
|
||||||
|
9.467012 16.430840 9.764743 16.133110 10.132012 16.133110 c
|
||||||
|
10.499282 16.133110 10.797012 16.430840 10.797012 16.798109 c
|
||||||
|
10.797012 17.703321 l
|
||||||
|
14.317344 17.386963 17.120886 14.583434 17.437263 11.063108 c
|
||||||
|
16.532019 11.063108 l
|
||||||
|
16.164749 11.063108 15.867019 10.765378 15.867019 10.398108 c
|
||||||
|
15.867019 10.030839 16.164749 9.733109 16.532019 9.733109 c
|
||||||
|
17.437273 9.733109 l
|
||||||
|
17.120937 6.212737 14.317376 3.409161 10.797012 3.092800 c
|
||||||
|
10.797012 3.998110 l
|
||||||
|
10.797012 4.365379 10.499282 4.663109 10.132012 4.663109 c
|
||||||
|
9.764743 4.663109 9.467012 4.365379 9.467012 3.998110 c
|
||||||
|
9.467012 3.092798 l
|
||||||
|
5.946643 3.409155 3.143077 6.212733 2.826741 9.733109 c
|
||||||
|
3.732019 9.733109 l
|
||||||
|
4.099288 9.733109 4.397019 10.030839 4.397019 10.398108 c
|
||||||
|
4.397019 10.765378 4.099288 11.063108 3.732019 11.063108 c
|
||||||
|
2.826750 11.063108 l
|
||||||
|
3.143129 14.583438 5.946676 17.386969 9.467012 17.703321 c
|
||||||
|
9.467012 16.798109 l
|
||||||
|
h
|
||||||
|
10.797012 19.037922 m
|
||||||
|
10.797012 19.998110 l
|
||||||
|
10.797012 20.365379 10.499282 20.663109 10.132012 20.663109 c
|
||||||
|
9.764743 20.663109 9.467012 20.365379 9.467012 19.998110 c
|
||||||
|
9.467012 19.037922 l
|
||||||
|
5.211674 18.714972 1.815125 15.318439 1.492149 11.063108 c
|
||||||
|
0.532019 11.063108 l
|
||||||
|
0.164750 11.063108 -0.132981 10.765378 -0.132981 10.398108 c
|
||||||
|
-0.132981 10.030839 0.164750 9.733109 0.532019 9.733109 c
|
||||||
|
1.492141 9.733109 l
|
||||||
|
1.815073 5.477732 5.211642 2.081148 9.467012 1.758196 c
|
||||||
|
9.467012 0.798109 l
|
||||||
|
9.467012 0.430840 9.764743 0.133108 10.132012 0.133108 c
|
||||||
|
10.499282 0.133108 10.797012 0.430840 10.797012 0.798109 c
|
||||||
|
10.797012 1.758198 l
|
||||||
|
15.052378 2.081156 18.448942 5.477736 18.771873 9.733109 c
|
||||||
|
19.732019 9.733109 l
|
||||||
|
20.099289 9.733109 20.397018 10.030839 20.397018 10.398108 c
|
||||||
|
20.397018 10.765378 20.099289 11.063108 19.732019 11.063108 c
|
||||||
|
18.771868 11.063108 l
|
||||||
|
18.448893 15.318436 15.052345 18.714966 10.797012 19.037922 c
|
||||||
|
h
|
||||||
|
10.132013 14.132962 m
|
||||||
|
9.173799 14.132962 8.397013 13.356176 8.397013 12.397963 c
|
||||||
|
8.397013 11.439748 9.173799 10.662962 10.132013 10.662962 c
|
||||||
|
11.090227 10.662962 11.867013 11.439748 11.867013 12.397963 c
|
||||||
|
11.867013 13.356176 11.090227 14.132962 10.132013 14.132962 c
|
||||||
|
h
|
||||||
|
7.067013 12.397963 m
|
||||||
|
7.067013 14.090715 8.439260 15.462962 10.132013 15.462962 c
|
||||||
|
11.824766 15.462962 13.197013 14.090715 13.197013 12.397963 c
|
||||||
|
13.197013 10.705210 11.824766 9.332962 10.132013 9.332962 c
|
||||||
|
8.439260 9.332962 7.067013 10.705210 7.067013 12.397963 c
|
||||||
|
h
|
||||||
|
6.310586 5.946628 m
|
||||||
|
6.984863 6.676261 8.128437 7.332962 10.132026 7.332962 c
|
||||||
|
12.135614 7.332962 13.279188 6.676261 13.953466 5.946628 c
|
||||||
|
14.202730 5.676899 14.623459 5.660309 14.893188 5.909575 c
|
||||||
|
15.162916 6.158839 15.179506 6.579567 14.930241 6.849297 c
|
||||||
|
13.975744 7.882154 12.462423 8.662962 10.132026 8.662962 c
|
||||||
|
7.801628 8.662962 6.288308 7.882154 5.333811 6.849297 c
|
||||||
|
5.084546 6.579567 5.101135 6.158839 5.370864 5.909575 c
|
||||||
|
5.640593 5.660309 6.061321 5.676899 6.310586 5.946628 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
2949
|
||||||
|
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
|
||||||
|
0000003039 00000 n
|
||||||
|
0000003062 00000 n
|
||||||
|
0000003235 00000 n
|
||||||
|
0000003309 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
3368
|
||||||
|
%%EOF
|
@ -136,7 +136,10 @@ private enum AttachmentFileEntry: ItemListNodeEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func attachmentFileControllerEntries(presentationData: PresentationData, recentDocuments: [Message]?) -> [AttachmentFileEntry] {
|
private func attachmentFileControllerEntries(presentationData: PresentationData, recentDocuments: [Message]?, empty: Bool) -> [AttachmentFileEntry] {
|
||||||
|
guard !empty else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
var entries: [AttachmentFileEntry] = []
|
var entries: [AttachmentFileEntry] = []
|
||||||
entries.append(.selectFromGallery(presentationData.theme, presentationData.strings.Attachment_SelectFromGallery))
|
entries.append(.selectFromGallery(presentationData.theme, presentationData.strings.Attachment_SelectFromGallery))
|
||||||
entries.append(.selectFromFiles(presentationData.theme, presentationData.strings.Attachment_SelectFromFiles))
|
entries.append(.selectFromFiles(presentationData.theme, presentationData.strings.Attachment_SelectFromFiles))
|
||||||
@ -152,7 +155,7 @@ private func attachmentFileControllerEntries(presentationData: PresentationData,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
entries.append(.recentHeader(presentationData.theme, presentationData.strings.Attachment_RecentlySentFiles.uppercased()))
|
entries.append(.recentHeader(presentationData.theme, presentationData.strings.Attachment_RecentlySentFiles.uppercased()))
|
||||||
for i in 0 ..< 8 {
|
for i in 0 ..< 11 {
|
||||||
entries.append(.file(Int32(i), presentationData.theme, nil))
|
entries.append(.file(Int32(i), presentationData.theme, nil))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -162,19 +165,25 @@ private func attachmentFileControllerEntries(presentationData: PresentationData,
|
|||||||
|
|
||||||
private class AttachmentFileControllerImpl: ItemListController, AttachmentContainable {
|
private class AttachmentFileControllerImpl: ItemListController, AttachmentContainable {
|
||||||
public var requestAttachmentMenuExpansion: () -> Void = {}
|
public var requestAttachmentMenuExpansion: () -> Void = {}
|
||||||
|
public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> [AttachmentContainable]) -> Void = { _ in }
|
||||||
|
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
|
||||||
|
|
||||||
var prepareForReuseImpl: () -> Void = {}
|
var resetForReuseImpl: () -> Void = {}
|
||||||
public func resetForReuse() {
|
public func resetForReuse() {
|
||||||
self.prepareForReuseImpl()
|
self.resetForReuseImpl()
|
||||||
self.scrollToTop?()
|
self.scrollToTop?()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func prepareForReuse() {
|
||||||
|
self.visibleBottomContentOffsetChanged?(self.visibleBottomContentOffset)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct AttachmentFileControllerState: Equatable {
|
private struct AttachmentFileControllerState: Equatable {
|
||||||
var searching: Bool
|
var searching: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
public func attachmentFileController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, presentGallery: @escaping () -> Void, presentFiles: @escaping () -> Void, send: @escaping (AnyMediaReference) -> Void) -> AttachmentContainable {
|
public func attachmentFileController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, bannedSendMedia: (Int32, Bool)?, presentGallery: @escaping () -> Void, presentFiles: @escaping () -> Void, send: @escaping (AnyMediaReference) -> Void) -> AttachmentContainable {
|
||||||
let actionsDisposable = DisposableSet()
|
let actionsDisposable = DisposableSet()
|
||||||
|
|
||||||
let statePromise = ValuePromise(AttachmentFileControllerState(searching: false), ignoreRepeated: true)
|
let statePromise = ValuePromise(AttachmentFileControllerState(searching: false), ignoreRepeated: true)
|
||||||
@ -236,9 +245,8 @@ public func attachmentFileController(context: AccountContext, updatedPresentatio
|
|||||||
}
|
}
|
||||||
|
|
||||||
var rightNavigationButton: ItemListNavigationButton?
|
var rightNavigationButton: ItemListNavigationButton?
|
||||||
if let recentDocuments = recentDocuments, recentDocuments.count > 10 {
|
if bannedSendMedia == nil && (recentDocuments == nil || (recentDocuments?.count ?? 0) > 10) {
|
||||||
rightNavigationButton = ItemListNavigationButton(content: .icon(.search), style: .regular, enabled: true, action: {
|
rightNavigationButton = ItemListNavigationButton(content: .icon(.search), style: .regular, enabled: true, action: {
|
||||||
expandImpl?()
|
|
||||||
updateState { state in
|
updateState { state in
|
||||||
var updatedState = state
|
var updatedState = state
|
||||||
updatedState.searching = true
|
updatedState.searching = true
|
||||||
@ -252,13 +260,25 @@ public func attachmentFileController(context: AccountContext, updatedPresentatio
|
|||||||
}), rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
|
}), rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
|
||||||
|
|
||||||
var emptyItem: AttachmentFileEmptyStateItem?
|
var emptyItem: AttachmentFileEmptyStateItem?
|
||||||
if let recentDocuments = recentDocuments, recentDocuments.isEmpty {
|
if let (untilDate, personal) = bannedSendMedia {
|
||||||
emptyItem = AttachmentFileEmptyStateItem(context: context, theme: presentationData.theme, strings: presentationData.strings)
|
let banDescription: String
|
||||||
|
if untilDate != 0 && untilDate != Int32.max {
|
||||||
|
banDescription = presentationData.strings.Conversation_RestrictedMediaTimed(stringForFullDate(timestamp: untilDate, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat)).string
|
||||||
|
} else if personal {
|
||||||
|
banDescription = presentationData.strings.Conversation_RestrictedMedia
|
||||||
|
} else {
|
||||||
|
banDescription = presentationData.strings.Conversation_DefaultRestrictedMedia
|
||||||
|
}
|
||||||
|
emptyItem = AttachmentFileEmptyStateItem(context: context, theme: presentationData.theme, strings: presentationData.strings, content: .bannedSendMedia(banDescription))
|
||||||
|
} else if let recentDocuments = recentDocuments, recentDocuments.isEmpty {
|
||||||
|
emptyItem = AttachmentFileEmptyStateItem(context: context, theme: presentationData.theme, strings: presentationData.strings, content: .intro)
|
||||||
}
|
}
|
||||||
|
|
||||||
var searchItem: ItemListControllerSearch?
|
var searchItem: ItemListControllerSearch?
|
||||||
if state.searching {
|
if state.searching {
|
||||||
searchItem = AttachmentFileSearchItem(context: context, presentationData: presentationData, cancel: {
|
searchItem = AttachmentFileSearchItem(context: context, presentationData: presentationData, focus: {
|
||||||
|
expandImpl?()
|
||||||
|
}, cancel: {
|
||||||
updateState { state in
|
updateState { state in
|
||||||
var updatedState = state
|
var updatedState = state
|
||||||
updatedState.searching = false
|
updatedState.searching = false
|
||||||
@ -271,7 +291,7 @@ public func attachmentFileController(context: AccountContext, updatedPresentatio
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: attachmentFileControllerEntries(presentationData: presentationData, recentDocuments: recentDocuments), style: .blocks, emptyStateItem: emptyItem, searchItem: searchItem, crossfadeState: crossfade, animateChanges: animateChanges)
|
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: attachmentFileControllerEntries(presentationData: presentationData, recentDocuments: recentDocuments, empty: bannedSendMedia != nil), style: .blocks, emptyStateItem: emptyItem, searchItem: searchItem, crossfadeState: crossfade, animateChanges: animateChanges)
|
||||||
|
|
||||||
return (controllerState, (listState, arguments))
|
return (controllerState, (listState, arguments))
|
||||||
} |> afterDisposed {
|
} |> afterDisposed {
|
||||||
@ -279,7 +299,16 @@ public func attachmentFileController(context: AccountContext, updatedPresentatio
|
|||||||
}
|
}
|
||||||
|
|
||||||
let controller = AttachmentFileControllerImpl(context: context, state: signal)
|
let controller = AttachmentFileControllerImpl(context: context, state: signal)
|
||||||
controller.prepareForReuseImpl = {
|
controller.visibleBottomContentOffsetChanged = { [weak controller] offset in
|
||||||
|
switch offset {
|
||||||
|
case let .known(value):
|
||||||
|
let backgroundAlpha: CGFloat = min(30.0, value) / 30.0
|
||||||
|
controller?.updateTabBarAlpha(backgroundAlpha, .immediate)
|
||||||
|
case .unknown, .none:
|
||||||
|
controller?.updateTabBarAlpha(1.0, .immediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
controller.resetForReuseImpl = {
|
||||||
updateState { state in
|
updateState { state in
|
||||||
var updatedState = state
|
var updatedState = state
|
||||||
updatedState.searching = false
|
updatedState.searching = false
|
||||||
|
@ -10,19 +10,26 @@ import TelegramAnimatedStickerNode
|
|||||||
import AccountContext
|
import AccountContext
|
||||||
|
|
||||||
final class AttachmentFileEmptyStateItem: ItemListControllerEmptyStateItem {
|
final class AttachmentFileEmptyStateItem: ItemListControllerEmptyStateItem {
|
||||||
|
enum Content: Equatable {
|
||||||
|
case intro
|
||||||
|
case bannedSendMedia(String)
|
||||||
|
}
|
||||||
|
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let strings: PresentationStrings
|
let strings: PresentationStrings
|
||||||
|
let content: Content
|
||||||
|
|
||||||
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings) {
|
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, content: Content) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
|
self.content = content
|
||||||
}
|
}
|
||||||
|
|
||||||
func isEqual(to: ItemListControllerEmptyStateItem) -> Bool {
|
func isEqual(to: ItemListControllerEmptyStateItem) -> Bool {
|
||||||
if let item = to as? AttachmentFileEmptyStateItem {
|
if let item = to as? AttachmentFileEmptyStateItem {
|
||||||
return self.theme === item.theme && self.strings === item.strings
|
return self.theme === item.theme && self.strings === item.strings && self.content == item.content
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -75,22 +82,32 @@ final class AttachmentFileEmptyStateItemNode: ItemListControllerEmptyStateItemNo
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
|
private func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
|
||||||
self.textNode.attributedText = NSAttributedString(string: strings.Attachment_FilesIntro, font: Font.regular(15.0), textColor: theme.list.freeTextColor, paragraphAlignment: .center)
|
let text: String
|
||||||
|
switch self.item.content {
|
||||||
|
case .intro:
|
||||||
|
text = strings.Attachment_FilesIntro
|
||||||
|
case let .bannedSendMedia(banDescription):
|
||||||
|
text = banDescription
|
||||||
|
}
|
||||||
|
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: theme.list.freeTextColor, paragraphAlignment: .center)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func updateLayout(layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
override func updateLayout(layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
self.validLayout = (layout, navigationBarHeight)
|
self.validLayout = (layout, navigationBarHeight)
|
||||||
var insets = layout.insets(options: [])
|
var insets = layout.insets(options: [])
|
||||||
insets.top += navigationBarHeight - 92.0
|
insets.top += navigationBarHeight
|
||||||
|
|
||||||
let imageSpacing: CGFloat = 12.0
|
let imageSpacing: CGFloat = 12.0
|
||||||
|
|
||||||
let imageSize = CGSize(width: 144.0, height: 144.0)
|
let imageSize = CGSize(width: 144.0, height: 144.0)
|
||||||
let imageHeight = layout.size.width < layout.size.height ? imageSize.height + imageSpacing : 0.0
|
let imageHeight = layout.size.width < layout.size.height ? imageSize.height + imageSpacing : 0.0
|
||||||
|
if !imageHeight.isZero {
|
||||||
self.animationNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - imageSize.width) / 2.0), y: -10.0), size: imageSize)
|
if case .intro = self.item.content {
|
||||||
self.animationNode.updateLayout(size: imageSize)
|
insets.top -= 92.0
|
||||||
|
} else {
|
||||||
|
insets.top -= 160.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let textSize = self.textNode.measure(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 70.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
let textSize = self.textNode.measure(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 70.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
||||||
|
|
||||||
let totalHeight = imageHeight + textSize.height
|
let totalHeight = imageHeight + textSize.height
|
||||||
@ -98,6 +115,8 @@ final class AttachmentFileEmptyStateItemNode: ItemListControllerEmptyStateItemNo
|
|||||||
|
|
||||||
transition.updateAlpha(node: self.animationNode, alpha: imageHeight > 0.0 ? 1.0 : 0.0)
|
transition.updateAlpha(node: self.animationNode, alpha: imageHeight > 0.0 ? 1.0 : 0.0)
|
||||||
transition.updateFrame(node: self.animationNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - imageSize.width) / 2.0), y: topOffset), size: imageSize))
|
transition.updateFrame(node: self.animationNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - imageSize.width) / 2.0), y: topOffset), size: imageSize))
|
||||||
|
self.animationNode.updateLayout(size: imageSize)
|
||||||
|
|
||||||
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((layout.size.width - textSize.width - layout.safeInsets.left - layout.safeInsets.right) / 2.0), y: topOffset + imageHeight), size: textSize))
|
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((layout.size.width - textSize.width - layout.safeInsets.left - layout.safeInsets.right) / 2.0), y: topOffset + imageHeight), size: textSize))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ private final class AttachmentFileSearchNavigationContentNode: NavigationBarCont
|
|||||||
private var theme: PresentationTheme
|
private var theme: PresentationTheme
|
||||||
private let strings: PresentationStrings
|
private let strings: PresentationStrings
|
||||||
|
|
||||||
|
private let focus: () -> Void
|
||||||
private let cancel: () -> Void
|
private let cancel: () -> Void
|
||||||
|
|
||||||
private let searchBar: SearchBarNode
|
private let searchBar: SearchBarNode
|
||||||
@ -34,10 +35,11 @@ private final class AttachmentFileSearchNavigationContentNode: NavigationBarCont
|
|||||||
self.searchBar.activity = activity
|
self.searchBar.activity = activity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
init(theme: PresentationTheme, strings: PresentationStrings, cancel: @escaping () -> Void, updateActivity: @escaping(@escaping(Bool)->Void) -> Void) {
|
init(theme: PresentationTheme, strings: PresentationStrings, focus: @escaping () -> Void, cancel: @escaping () -> Void, updateActivity: @escaping(@escaping(Bool)->Void) -> Void) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
|
|
||||||
|
self.focus = focus
|
||||||
self.cancel = cancel
|
self.cancel = cancel
|
||||||
|
|
||||||
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: theme, hasSeparator: false), strings: strings, fieldStyle: .modern, displayBackground: false)
|
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: theme, hasSeparator: false), strings: strings, fieldStyle: .modern, displayBackground: false)
|
||||||
@ -45,7 +47,7 @@ private final class AttachmentFileSearchNavigationContentNode: NavigationBarCont
|
|||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.addSubnode(self.searchBar)
|
self.addSubnode(self.searchBar)
|
||||||
|
|
||||||
self.searchBar.cancel = { [weak self] in
|
self.searchBar.cancel = { [weak self] in
|
||||||
self?.searchBar.deactivate(clear: false)
|
self?.searchBar.deactivate(clear: false)
|
||||||
self?.cancel()
|
self?.cancel()
|
||||||
@ -55,6 +57,12 @@ private final class AttachmentFileSearchNavigationContentNode: NavigationBarCont
|
|||||||
self?.queryUpdated?(query)
|
self?.queryUpdated?(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.searchBar.focusUpdated = { [weak self] focus in
|
||||||
|
if focus {
|
||||||
|
self?.focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateActivity({ [weak self] value in
|
updateActivity({ [weak self] value in
|
||||||
self?.activity = value
|
self?.activity = value
|
||||||
})
|
})
|
||||||
@ -99,6 +107,7 @@ private final class AttachmentFileSearchNavigationContentNode: NavigationBarCont
|
|||||||
final class AttachmentFileSearchItem: ItemListControllerSearch {
|
final class AttachmentFileSearchItem: ItemListControllerSearch {
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let presentationData: PresentationData
|
let presentationData: PresentationData
|
||||||
|
let focus: () -> Void
|
||||||
let cancel: () -> Void
|
let cancel: () -> Void
|
||||||
let send: (Message) -> Void
|
let send: (Message) -> Void
|
||||||
let dismissInput: () -> Void
|
let dismissInput: () -> Void
|
||||||
@ -107,9 +116,10 @@ final class AttachmentFileSearchItem: ItemListControllerSearch {
|
|||||||
private var activity: ValuePromise<Bool> = ValuePromise(ignoreRepeated: false)
|
private var activity: ValuePromise<Bool> = ValuePromise(ignoreRepeated: false)
|
||||||
private let activityDisposable = MetaDisposable()
|
private let activityDisposable = MetaDisposable()
|
||||||
|
|
||||||
init(context: AccountContext, presentationData: PresentationData, cancel: @escaping () -> Void, send: @escaping (Message) -> Void, dismissInput: @escaping () -> Void) {
|
init(context: AccountContext, presentationData: PresentationData, focus: @escaping () -> Void, cancel: @escaping () -> Void, send: @escaping (Message) -> Void, dismissInput: @escaping () -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
|
self.focus = focus
|
||||||
self.cancel = cancel
|
self.cancel = cancel
|
||||||
self.send = send
|
self.send = send
|
||||||
self.dismissInput = dismissInput
|
self.dismissInput = dismissInput
|
||||||
@ -145,7 +155,7 @@ final class AttachmentFileSearchItem: ItemListControllerSearch {
|
|||||||
current.updateTheme(presentationData.theme)
|
current.updateTheme(presentationData.theme)
|
||||||
return current
|
return current
|
||||||
} else {
|
} else {
|
||||||
return AttachmentFileSearchNavigationContentNode(theme: presentationData.theme, strings: presentationData.strings, cancel: self.cancel, updateActivity: { [weak self] value in
|
return AttachmentFileSearchNavigationContentNode(theme: presentationData.theme, strings: presentationData.strings, focus: self.focus, cancel: self.cancel, updateActivity: { [weak self] value in
|
||||||
self?.updateActivity = value
|
self?.updateActivity = value
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -10267,13 +10267,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let storeEditedPhotos = settings.storeEditedPhotos
|
let storeEditedPhotos = settings.storeEditedPhotos
|
||||||
let inputText = strongSelf.presentationInterfaceState.interfaceState.effectiveInputState.inputText
|
let inputText = strongSelf.presentationInterfaceState.interfaceState.effectiveInputState.inputText
|
||||||
|
|
||||||
presentedLegacyCamera(context: strongSelf.context, peer: peer, chatLocation: strongSelf.chatLocation, cameraView: cameraView, menuController: nil, parentController: strongSelf, editingMedia: false, saveCapturedPhotos: storeEditedPhotos, mediaGrouping: true, initialCaption: inputText.string, hasSchedule: strongSelf.presentationInterfaceState.subject != .scheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, photoOnly: photoOnly, sendMessagesWithSignals: { [weak self] signals, silentPosting, scheduleTime in
|
presentedLegacyCamera(context: strongSelf.context, peer: peer, chatLocation: strongSelf.chatLocation, cameraView: cameraView, menuController: nil, parentController: strongSelf, attachmentController: self?.attachmentController, editingMedia: false, saveCapturedPhotos: storeEditedPhotos, mediaGrouping: true, initialCaption: inputText.string, hasSchedule: strongSelf.presentationInterfaceState.subject != .scheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, photoOnly: photoOnly, sendMessagesWithSignals: { [weak self] signals, silentPosting, scheduleTime in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
// if editMediaOptions != nil {
|
strongSelf.enqueueMediaMessages(signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime > 0 ? scheduleTime : nil)
|
||||||
// strongSelf.editMessageMediaWithLegacySignals(signals!)
|
|
||||||
// } else {
|
|
||||||
strongSelf.enqueueMediaMessages(signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime > 0 ? scheduleTime : nil)
|
|
||||||
// }
|
|
||||||
if !inputText.string.isEmpty {
|
if !inputText.string.isEmpty {
|
||||||
strongSelf.clearInputText()
|
strongSelf.clearInputText()
|
||||||
}
|
}
|
||||||
@ -10316,6 +10312,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
return self?.getCaptionPanelView()
|
return self?.getCaptionPanelView()
|
||||||
}, dismissedWithResult: { [weak self] in
|
}, dismissedWithResult: { [weak self] in
|
||||||
self?.attachmentController?.dismiss(animated: false, completion: nil)
|
self?.attachmentController?.dismiss(animated: false, completion: nil)
|
||||||
|
}, finishedTransitionIn: { [weak self] in
|
||||||
|
self?.attachmentController?.scrollToTop?()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -10348,7 +10346,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
var availableTabs: [AttachmentButtonType] = [.gallery, .file, .location, .contact]
|
var availableTabs: [AttachmentButtonType] = [.gallery, .file, .location, .contact]
|
||||||
if canSendPolls {
|
if canSendPolls {
|
||||||
availableTabs.append(.poll)
|
availableTabs.insert(.poll, at: availableTabs.count - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
let inputText = self.presentationInterfaceState.interfaceState.effectiveInputState.inputText
|
let inputText = self.presentationInterfaceState.interfaceState.effectiveInputState.inputText
|
||||||
@ -10367,12 +10365,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
strongSelf.controllerNavigationDisposable.set(nil)
|
strongSelf.controllerNavigationDisposable.set(nil)
|
||||||
let existingController = currentMediaController.with { $0 }
|
let existingController = currentMediaController.with { $0 }
|
||||||
if let controller = existingController {
|
if let controller = existingController {
|
||||||
controller.prepareForReuse()
|
|
||||||
completion(controller, nil)
|
completion(controller, nil)
|
||||||
|
controller.prepareForReuse()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.presentMediaPicker(bannedSendMedia: bannedSendMedia, present: { controller, mediaPickerContext in
|
strongSelf.presentMediaPicker(bannedSendMedia: bannedSendMedia, present: { controller, mediaPickerContext in
|
||||||
let _ = currentMediaController.swap(controller)
|
let _ = currentMediaController.swap(controller)
|
||||||
|
mediaPickerContext?.setCaption(inputText)
|
||||||
completion(controller, mediaPickerContext)
|
completion(controller, mediaPickerContext)
|
||||||
}, updateMediaPickerContext: { [weak attachmentController] mediaPickerContext in
|
}, updateMediaPickerContext: { [weak attachmentController] mediaPickerContext in
|
||||||
attachmentController?.mediaPickerContext = mediaPickerContext
|
attachmentController?.mediaPickerContext = mediaPickerContext
|
||||||
@ -10387,9 +10386,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let existingController = currentFilesController.with { $0 }
|
let existingController = currentFilesController.with { $0 }
|
||||||
if let controller = existingController {
|
if let controller = existingController {
|
||||||
completion(controller, nil)
|
completion(controller, nil)
|
||||||
|
controller.prepareForReuse()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let controller = attachmentFileController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, presentGallery: { [weak self, weak attachmentController] in
|
let controller = attachmentFileController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, bannedSendMedia: bannedSendMedia, presentGallery: { [weak self, weak attachmentController] in
|
||||||
attachmentController?.dismiss(animated: true)
|
attachmentController?.dismiss(animated: true)
|
||||||
self?.presentFileGallery()
|
self?.presentFileGallery()
|
||||||
}, presentFiles: { [weak self, weak attachmentController] in
|
}, presentFiles: { [weak self, weak attachmentController] in
|
||||||
@ -10415,6 +10415,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let existingController = currentLocationController.with { $0 }
|
let existingController = currentLocationController.with { $0 }
|
||||||
if let controller = existingController {
|
if let controller = existingController {
|
||||||
completion(controller, nil)
|
completion(controller, nil)
|
||||||
|
controller.prepareForReuse()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let selfPeerId: PeerId
|
let selfPeerId: PeerId
|
||||||
@ -10463,9 +10464,21 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
completion(contactsController, contactsController.mediaPickerContext)
|
completion(contactsController, contactsController.mediaPickerContext)
|
||||||
strongSelf.controllerNavigationDisposable.set((contactsController.result
|
strongSelf.controllerNavigationDisposable.set((contactsController.result
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] peers in
|
|> deliverOnMainQueue).start(next: { [weak self] peers in
|
||||||
if let strongSelf = self, let (peers, _, silent, scheduleTime) = peers {
|
if let strongSelf = self, let (peers, _, silent, scheduleTime, text) = peers {
|
||||||
|
var textEnqueueMessage: EnqueueMessage?
|
||||||
|
if let text = text, text.length > 0 {
|
||||||
|
var attributes: [MessageAttribute] = []
|
||||||
|
let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text))
|
||||||
|
if !entities.isEmpty {
|
||||||
|
attributes.append(TextEntitiesMessageAttribute(entities: entities))
|
||||||
|
}
|
||||||
|
textEnqueueMessage = .message(text: text.string, attributes: attributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)
|
||||||
|
}
|
||||||
if peers.count > 1 {
|
if peers.count > 1 {
|
||||||
var enqueueMessages: [EnqueueMessage] = []
|
var enqueueMessages: [EnqueueMessage] = []
|
||||||
|
if let textEnqueueMessage = textEnqueueMessage {
|
||||||
|
enqueueMessages.append(textEnqueueMessage)
|
||||||
|
}
|
||||||
for peer in peers {
|
for peer in peers {
|
||||||
var media: TelegramMediaContact?
|
var media: TelegramMediaContact?
|
||||||
switch peer {
|
switch peer {
|
||||||
@ -10555,8 +10568,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, nil)
|
}, nil)
|
||||||
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil)
|
|
||||||
strongSelf.sendMessages(strongSelf.transformEnqueueMessages([message], silentPosting: silent, scheduleTime: scheduleTime))
|
var enqueueMessages: [EnqueueMessage] = []
|
||||||
|
if let textEnqueueMessage = textEnqueueMessage {
|
||||||
|
enqueueMessages.append(textEnqueueMessage)
|
||||||
|
}
|
||||||
|
enqueueMessages.append(.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil))
|
||||||
|
strongSelf.sendMessages(strongSelf.transformEnqueueMessages(enqueueMessages, silentPosting: silent, scheduleTime: scheduleTime))
|
||||||
} else {
|
} else {
|
||||||
let contactController = strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .filter(peer: peerAndContactData.0, contactId: nil, contactData: contactData, completion: { peer, contactData in
|
let contactController = strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .filter(peer: peerAndContactData.0, contactId: nil, contactData: contactData, completion: { peer, contactData in
|
||||||
guard let strongSelf = self, !contactData.basicData.phoneNumbers.isEmpty else {
|
guard let strongSelf = self, !contactData.basicData.phoneNumbers.isEmpty else {
|
||||||
@ -10573,8 +10591,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, nil)
|
}, nil)
|
||||||
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil)
|
|
||||||
strongSelf.sendMessages(strongSelf.transformEnqueueMessages([message], silentPosting: silent, scheduleTime: scheduleTime))
|
var enqueueMessages: [EnqueueMessage] = []
|
||||||
|
if let textEnqueueMessage = textEnqueueMessage {
|
||||||
|
enqueueMessages.append(textEnqueueMessage)
|
||||||
|
}
|
||||||
|
enqueueMessages.append(.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil))
|
||||||
|
strongSelf.sendMessages(strongSelf.transformEnqueueMessages(enqueueMessages, silentPosting: silent, scheduleTime: scheduleTime))
|
||||||
}
|
}
|
||||||
}), completed: nil, cancelled: nil)
|
}), completed: nil, cancelled: nil)
|
||||||
strongSelf.effectiveNavigationController?.pushViewController(contactController)
|
strongSelf.effectiveNavigationController?.pushViewController(contactController)
|
||||||
@ -11007,10 +11030,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
controller.openCamera = { [weak self] cameraView in
|
controller.openCamera = { [weak self] cameraView in
|
||||||
self?.openCamera(cameraView: cameraView)
|
self?.openCamera(cameraView: cameraView)
|
||||||
}
|
}
|
||||||
controller.presentWebSearch = { [weak self, weak controller] in
|
controller.presentWebSearch = { [weak self, weak controller] mediaGroups in
|
||||||
self?.presentWebSearch(editingMessage: false, attachment: true, present: { [weak controller] c, a in
|
self?.presentWebSearch(editingMessage: false, attachment: true, present: { [weak controller] c, a in
|
||||||
controller?.present(c, in: .current)
|
controller?.present(c, in: .current)
|
||||||
if let webSearchController = c as? WebSearchController {
|
if let webSearchController = c as? WebSearchController {
|
||||||
|
webSearchController.searchingUpdated = { [weak mediaGroups] searching in
|
||||||
|
if let mediaGroups = mediaGroups, mediaGroups.isNodeLoaded {
|
||||||
|
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
|
||||||
|
transition.updateAlpha(node: mediaGroups.displayNode, alpha: searching ? 0.0 : 1.0)
|
||||||
|
mediaGroups.displayNode.isUserInteractionEnabled = !searching
|
||||||
|
}
|
||||||
|
}
|
||||||
|
webSearchController.present(mediaGroups, in: .current)
|
||||||
webSearchController.dismissed = {
|
webSearchController.dismissed = {
|
||||||
updateMediaPickerContext(mediaPickerContext)
|
updateMediaPickerContext(mediaPickerContext)
|
||||||
}
|
}
|
||||||
@ -11292,7 +11323,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
self.effectiveNavigationController?.pushViewController(contactsController)
|
self.effectiveNavigationController?.pushViewController(contactsController)
|
||||||
self.controllerNavigationDisposable.set((contactsController.result
|
self.controllerNavigationDisposable.set((contactsController.result
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] peers in
|
|> deliverOnMainQueue).start(next: { [weak self] peers in
|
||||||
if let strongSelf = self, let (peers, _, _, _) = peers {
|
if let strongSelf = self, let (peers, _, _, _, _) = peers {
|
||||||
if peers.count > 1 {
|
if peers.count > 1 {
|
||||||
var enqueueMessages: [EnqueueMessage] = []
|
var enqueueMessages: [EnqueueMessage] = []
|
||||||
for peer in peers {
|
for peer in peers {
|
||||||
|
@ -868,6 +868,20 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
|
||||||
|
if let forwardBackgroundNode = strongSelf.forwardBackgroundNode {
|
||||||
|
transition.updateAlpha(node: forwardBackgroundNode, alpha: isPlaying ? 0.0 : 1.0)
|
||||||
|
}
|
||||||
|
if let replyBackgroundNode = strongSelf.replyBackgroundNode {
|
||||||
|
transition.updateAlpha(node: replyBackgroundNode, alpha: isPlaying ? 0.0 : 1.0)
|
||||||
|
}
|
||||||
|
if let forwardInfoNode = strongSelf.forwardInfoNode {
|
||||||
|
transition.updateAlpha(node: forwardInfoNode, alpha: isPlaying ? 0.0 : 1.0)
|
||||||
|
}
|
||||||
|
if let replyInfoNode = strongSelf.replyInfoNode {
|
||||||
|
transition.updateAlpha(node: replyInfoNode, alpha: isPlaying ? 0.0 : 1.0)
|
||||||
|
}
|
||||||
|
|
||||||
if let (_, f) = strongSelf.awaitingAppliedReaction {
|
if let (_, f) = strongSelf.awaitingAppliedReaction {
|
||||||
strongSelf.awaitingAppliedReaction = nil
|
strongSelf.awaitingAppliedReaction = nil
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ public class ComposeControllerImpl: ViewController, ComposeController {
|
|||||||
strongSelf.createActionDisposable.set((controller.result
|
strongSelf.createActionDisposable.set((controller.result
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue).start(next: { [weak controller] result in
|
|> deliverOnMainQueue).start(next: { [weak controller] result in
|
||||||
if let strongSelf = self, let (contactPeers, _, _, _) = result, case let .peer(peer, _, _) = contactPeers.first {
|
if let strongSelf = self, let (contactPeers, _, _, _, _) = result, case let .peer(peer, _, _) = contactPeers.first {
|
||||||
controller?.dismissSearch()
|
controller?.dismissSearch()
|
||||||
controller?.displayNavigationActivity = true
|
controller?.displayNavigationActivity = true
|
||||||
strongSelf.createActionDisposable.set((strongSelf.context.engine.peers.createSecretChat(peerId: peer.id) |> deliverOnMainQueue).start(next: { peerId in
|
strongSelf.createActionDisposable.set((strongSelf.context.engine.peers.createSecretChat(peerId: peer.id) |> deliverOnMainQueue).start(next: { peerId in
|
||||||
|
@ -43,8 +43,10 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
|||||||
return self._ready
|
return self._ready
|
||||||
}
|
}
|
||||||
|
|
||||||
private let _result = Promise<([ContactListPeer], ContactListAction, Bool, Int32?)?>()
|
fileprivate var caption: NSAttributedString?
|
||||||
var result: Signal<([ContactListPeer], ContactListAction, Bool, Int32?)?, NoError> {
|
|
||||||
|
private let _result = Promise<([ContactListPeer], ContactListAction, Bool, Int32?, NSAttributedString?)?>()
|
||||||
|
var result: Signal<([ContactListPeer], ContactListAction, Bool, Int32?, NSAttributedString?)?, NoError> {
|
||||||
return self._result.get()
|
return self._result.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,6 +76,8 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
|||||||
}
|
}
|
||||||
|
|
||||||
var requestAttachmentMenuExpansion: () -> Void = {}
|
var requestAttachmentMenuExpansion: () -> Void = {}
|
||||||
|
var updateNavigationStack: (@escaping ([AttachmentContainable]) -> [AttachmentContainable]) -> Void = { _ in }
|
||||||
|
var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
|
||||||
|
|
||||||
init(_ params: ContactSelectionControllerParams) {
|
init(_ params: ContactSelectionControllerParams) {
|
||||||
self.context = params.context
|
self.context = params.context
|
||||||
@ -199,6 +203,10 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.contactsNode.cancelSearch = { [weak self] in
|
||||||
|
self?.deactivateSearch()
|
||||||
|
}
|
||||||
|
|
||||||
self.contactsNode.dismiss = { [weak self] in
|
self.contactsNode.dismiss = { [weak self] in
|
||||||
self?.presentingViewController?.dismiss(animated: true, completion: nil)
|
self?.presentingViewController?.dismiss(animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
@ -220,7 +228,7 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
|||||||
self.contactsNode.requestMultipleAction = { [weak self] silent, scheduleTime in
|
self.contactsNode.requestMultipleAction = { [weak self] silent, scheduleTime in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let selectedPeers = strongSelf.contactsNode.contactListNode.selectedPeers
|
let selectedPeers = strongSelf.contactsNode.contactListNode.selectedPeers
|
||||||
strongSelf._result.set(.single((selectedPeers, .generic, silent, scheduleTime)))
|
strongSelf._result.set(.single((selectedPeers, .generic, silent, scheduleTime, strongSelf.caption)))
|
||||||
if strongSelf.autoDismiss {
|
if strongSelf.autoDismiss {
|
||||||
strongSelf.dismiss()
|
strongSelf.dismiss()
|
||||||
}
|
}
|
||||||
@ -307,6 +315,8 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
|||||||
if let searchContentNode = self.searchContentNode as? NavigationBarSearchContentNode {
|
if let searchContentNode = self.searchContentNode as? NavigationBarSearchContentNode {
|
||||||
self.contactsNode.deactivateSearch(placeholderNode: searchContentNode.placeholderNode)
|
self.contactsNode.deactivateSearch(placeholderNode: searchContentNode.placeholderNode)
|
||||||
}
|
}
|
||||||
|
} else if let searchContentNode = self.searchContentNode as? ContactsSearchNavigationContentNode {
|
||||||
|
searchContentNode.cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,7 +325,7 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
|||||||
self.confirmationDisposable.set((self.confirmation(peer) |> deliverOnMainQueue).start(next: { [weak self] value in
|
self.confirmationDisposable.set((self.confirmation(peer) |> deliverOnMainQueue).start(next: { [weak self] value in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if value {
|
if value {
|
||||||
strongSelf._result.set(.single(([peer], action, false, nil)))
|
strongSelf._result.set(.single(([peer], action, false, nil, nil)))
|
||||||
if strongSelf.autoDismiss {
|
if strongSelf.autoDismiss {
|
||||||
strongSelf.dismiss()
|
strongSelf.dismiss()
|
||||||
}
|
}
|
||||||
@ -377,6 +387,10 @@ final class ContactsSearchNavigationContentNode: NavigationBarContentNode {
|
|||||||
self.searchBar.deactivate(clear: false)
|
self.searchBar.deactivate(clear: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cancel() {
|
||||||
|
self.searchBar.cancel?()
|
||||||
|
}
|
||||||
|
|
||||||
func updateActivity(_ activity: Bool) {
|
func updateActivity(_ activity: Bool) {
|
||||||
self.searchBar.activity = activity
|
self.searchBar.activity = activity
|
||||||
}
|
}
|
||||||
@ -410,7 +424,7 @@ final class ContactsPickerContext: AttachmentMediaPickerContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setCaption(_ caption: NSAttributedString) {
|
func setCaption(_ caption: NSAttributedString) {
|
||||||
|
self.controller?.caption = caption
|
||||||
}
|
}
|
||||||
|
|
||||||
func send(silently: Bool, mode: AttachmentMediaPickerSendMode) {
|
func send(silently: Bool, mode: AttachmentMediaPickerSendMode) {
|
||||||
|
@ -38,6 +38,7 @@ final class ContactSelectionControllerNode: ASDisplayNode {
|
|||||||
var requestOpenPeerFromSearch: ((ContactListPeer) -> Void)?
|
var requestOpenPeerFromSearch: ((ContactListPeer) -> Void)?
|
||||||
var requestMultipleAction: ((_ silent: Bool, _ scheduleTime: Int32?) -> Void)?
|
var requestMultipleAction: ((_ silent: Bool, _ scheduleTime: Int32?) -> Void)?
|
||||||
var dismiss: (() -> Void)?
|
var dismiss: (() -> Void)?
|
||||||
|
var cancelSearch: (() -> Void)?
|
||||||
|
|
||||||
var presentationData: PresentationData {
|
var presentationData: PresentationData {
|
||||||
didSet {
|
didSet {
|
||||||
@ -216,6 +217,9 @@ final class ContactSelectionControllerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, contextAction: nil)
|
}, contextAction: nil)
|
||||||
|
searchContainerNode.cancel = { [weak self] in
|
||||||
|
self?.cancelSearch?()
|
||||||
|
}
|
||||||
self.insertSubnode(searchContainerNode, belowSubnode: navigationBar)
|
self.insertSubnode(searchContainerNode, belowSubnode: navigationBar)
|
||||||
self.searchContainerNode = searchContainerNode
|
self.searchContainerNode = searchContainerNode
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import ShareController
|
|||||||
import LegacyUI
|
import LegacyUI
|
||||||
import LegacyMediaPickerUI
|
import LegacyMediaPickerUI
|
||||||
|
|
||||||
func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: ChatLocation, cameraView: TGAttachmentCameraView?, menuController: TGMenuSheetController?, parentController: ViewController, editingMedia: Bool, saveCapturedPhotos: Bool, mediaGrouping: Bool, initialCaption: String, hasSchedule: Bool, photoOnly: Bool, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, recognizedQRCode: @escaping (String) -> Void = { _ in }, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, dismissedWithResult: @escaping () -> Void = {}) {
|
func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: ChatLocation, cameraView: TGAttachmentCameraView?, menuController: TGMenuSheetController?, parentController: ViewController, attachmentController: ViewController? = nil, editingMedia: Bool, saveCapturedPhotos: Bool, mediaGrouping: Bool, initialCaption: String, hasSchedule: Bool, photoOnly: Bool, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, recognizedQRCode: @escaping (String) -> Void = { _ in }, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, dismissedWithResult: @escaping () -> Void = {}, finishedTransitionIn: @escaping () -> Void = {}) {
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme)
|
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme)
|
||||||
legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .portrait, compactSize: .portrait)
|
legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .portrait, compactSize: .portrait)
|
||||||
@ -94,7 +94,9 @@ func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: Ch
|
|||||||
let screenSize = parentController.view.bounds.size
|
let screenSize = parentController.view.bounds.size
|
||||||
var startFrame = CGRect(x: 0, y: screenSize.height, width: screenSize.width, height: screenSize.height)
|
var startFrame = CGRect(x: 0, y: screenSize.height, width: screenSize.width, height: screenSize.height)
|
||||||
if let cameraView = cameraView {
|
if let cameraView = cameraView {
|
||||||
if let menuController = menuController {
|
if let attachmentController = attachmentController {
|
||||||
|
startFrame = attachmentController.view.convert(cameraView.previewView()!.frame, from: cameraView)
|
||||||
|
} else if let menuController = menuController {
|
||||||
startFrame = menuController.view.convert(cameraView.previewView()!.frame, from: cameraView)
|
startFrame = menuController.view.convert(cameraView.previewView()!.frame, from: cameraView)
|
||||||
} else {
|
} else {
|
||||||
startFrame = parentController.view.convert(cameraView.previewView()!.frame, from: cameraView)
|
startFrame = parentController.view.convert(cameraView.previewView()!.frame, from: cameraView)
|
||||||
@ -109,7 +111,9 @@ func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: Ch
|
|||||||
controller.view.disablesInteractiveTransitionGestureRecognizer = true
|
controller.view.disablesInteractiveTransitionGestureRecognizer = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
controller.finishedTransitionIn = {
|
||||||
|
finishedTransitionIn()
|
||||||
|
}
|
||||||
controller.beginTransitionOut = { [weak controller, weak cameraView] in
|
controller.beginTransitionOut = { [weak controller, weak cameraView] in
|
||||||
if let controller = controller, let cameraView = cameraView {
|
if let controller = controller, let cameraView = cameraView {
|
||||||
cameraView.willAttachPreviewView()
|
cameraView.willAttachPreviewView()
|
||||||
|
@ -8059,7 +8059,7 @@ func presentAddMembers(context: AccountContext, updatedPresentationData: (initia
|
|||||||
if let contactsController = contactsController as? ContactSelectionController {
|
if let contactsController = contactsController as? ContactSelectionController {
|
||||||
selectAddMemberDisposable.set((contactsController.result
|
selectAddMemberDisposable.set((contactsController.result
|
||||||
|> deliverOnMainQueue).start(next: { [weak contactsController] result in
|
|> deliverOnMainQueue).start(next: { [weak contactsController] result in
|
||||||
guard let (peers, _, _, _) = result, let memberPeer = peers.first else {
|
guard let (peers, _, _, _, _) = result, let memberPeer = peers.first else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,6 +164,8 @@ public final class WebSearchController: ViewController {
|
|||||||
|
|
||||||
public var dismissed: () -> Void = { }
|
public var dismissed: () -> Void = { }
|
||||||
|
|
||||||
|
public var searchingUpdated: (Bool) -> Void = { _ in }
|
||||||
|
|
||||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: EnginePeer?, chatLocation: ChatLocation?, configuration: SearchBotsConfiguration, mode: WebSearchControllerMode) {
|
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: EnginePeer?, chatLocation: ChatLocation?, configuration: SearchBotsConfiguration, mode: WebSearchControllerMode) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
@ -237,6 +239,7 @@ public final class WebSearchController: ViewController {
|
|||||||
navigationContentNode.setQueryUpdated { [weak self] query in
|
navigationContentNode.setQueryUpdated { [weak self] query in
|
||||||
if let strongSelf = self, strongSelf.isNodeLoaded {
|
if let strongSelf = self, strongSelf.isNodeLoaded {
|
||||||
strongSelf.updateSearchQuery(query)
|
strongSelf.updateSearchQuery(query)
|
||||||
|
strongSelf.searchingUpdated(!query.isEmpty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
navigationContentNode.cancel = { [weak self] in
|
navigationContentNode.cancel = { [weak self] in
|
||||||
@ -354,7 +357,7 @@ public final class WebSearchController: ViewController {
|
|||||||
if case let .media(attachmentValue, _) = self.mode, attachmentValue {
|
if case let .media(attachmentValue, _) = self.mode, attachmentValue {
|
||||||
attachment = true
|
attachment = true
|
||||||
}
|
}
|
||||||
self.displayNode = WebSearchControllerNode(context: self.context, presentationData: self.interfaceState.presentationData, controllerInteraction: self.controllerInteraction!, peer: self.peer, chatLocation: self.chatLocation, mode: self.mode.mode, attachment: attachment)
|
self.displayNode = WebSearchControllerNode(controller: self, context: self.context, presentationData: self.interfaceState.presentationData, controllerInteraction: self.controllerInteraction!, peer: self.peer, chatLocation: self.chatLocation, mode: self.mode.mode, attachment: attachment)
|
||||||
self.controllerNode.requestUpdateInterfaceState = { [weak self] animated, f in
|
self.controllerNode.requestUpdateInterfaceState = { [weak self] animated, f in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.updateInterfaceState(f)
|
strongSelf.updateInterfaceState(f)
|
||||||
@ -374,6 +377,8 @@ public final class WebSearchController: ViewController {
|
|||||||
|
|
||||||
self._ready.set(.single(true))
|
self._ready.set(.single(true))
|
||||||
self.displayNodeDidLoad()
|
self.displayNodeDidLoad()
|
||||||
|
|
||||||
|
self.controllerNode.updateBackgroundAlpha(0.0, transition: .immediate)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateInterfaceState(animated: Bool = true, _ f: (WebSearchInterfaceState) -> WebSearchInterfaceState) {
|
private func updateInterfaceState(animated: Bool = true, _ f: (WebSearchInterfaceState) -> WebSearchInterfaceState) {
|
||||||
@ -542,7 +547,8 @@ public final class WebSearchController: ViewController {
|
|||||||
|
|
||||||
self.validLayout = layout
|
self.validLayout = layout
|
||||||
|
|
||||||
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
|
let navigationBarHeight = self.navigationLayout(layout: layout).navigationFrame.maxY
|
||||||
|
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,8 +64,20 @@ private func preparedTransition(from fromEntries: [WebSearchEntry], to toEntries
|
|||||||
return WebSearchTransition(deleteItems: deleteIndices, insertItems: insertions, updateItems: updates, entryCount: toEntries.count, hasMore: hasMore)
|
return WebSearchTransition(deleteItems: deleteIndices, insertItems: insertions, updateItems: updates, entryCount: toEntries.count, hasMore: hasMore)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func gridNodeLayoutForContainerLayout(size: CGSize, insets: UIEdgeInsets) -> GridNodeLayoutType {
|
private func gridNodeLayoutForContainerLayout(_ layout: ContainerViewLayout) -> GridNodeLayoutType {
|
||||||
let side = floorToScreenPixels((size.width - insets.left - insets.right - 2.0) / 3.0)
|
let itemsPerRow: Int
|
||||||
|
if case .compact = layout.metrics.widthClass {
|
||||||
|
switch layout.orientation {
|
||||||
|
case .portrait:
|
||||||
|
itemsPerRow = 3
|
||||||
|
case .landscape:
|
||||||
|
itemsPerRow = 5
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
itemsPerRow = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
let side = floorToScreenPixels((layout.size.width - layout.safeInsets.left - layout.safeInsets.right - CGFloat(itemsPerRow - 1)) / CGFloat(itemsPerRow))
|
||||||
return .fixed(itemSize: CGSize(width: side, height: side), fillWidth: true, lineSpacing: 1.0, itemSpacing: 1.0)
|
return .fixed(itemSize: CGSize(width: side, height: side), fillWidth: true, lineSpacing: 1.0, itemSpacing: 1.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,6 +128,7 @@ private func preparedWebSearchRecentTransition(from fromEntries: [WebSearchRecen
|
|||||||
}
|
}
|
||||||
|
|
||||||
class WebSearchControllerNode: ASDisplayNode {
|
class WebSearchControllerNode: ASDisplayNode {
|
||||||
|
private weak var controller: WebSearchController?
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let peer: EnginePeer?
|
private let peer: EnginePeer?
|
||||||
private let chatLocation: ChatLocation?
|
private let chatLocation: ChatLocation?
|
||||||
@ -129,6 +142,7 @@ class WebSearchControllerNode: ASDisplayNode {
|
|||||||
private var webSearchInterfaceState: WebSearchInterfaceState
|
private var webSearchInterfaceState: WebSearchInterfaceState
|
||||||
private let webSearchInterfaceStatePromise: ValuePromise<WebSearchInterfaceState>
|
private let webSearchInterfaceStatePromise: ValuePromise<WebSearchInterfaceState>
|
||||||
|
|
||||||
|
private let segmentedContainerNode: ASDisplayNode
|
||||||
private let segmentedBackgroundNode: ASDisplayNode
|
private let segmentedBackgroundNode: ASDisplayNode
|
||||||
private let segmentedSeparatorNode: ASDisplayNode
|
private let segmentedSeparatorNode: ASDisplayNode
|
||||||
private let segmentedControlNode: SegmentedControlNode
|
private let segmentedControlNode: SegmentedControlNode
|
||||||
@ -173,7 +187,8 @@ class WebSearchControllerNode: ASDisplayNode {
|
|||||||
var presentStickers: ((@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?)?
|
var presentStickers: ((@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?)?
|
||||||
var getCaptionPanelView: () -> TGCaptionPanelView? = { return nil }
|
var getCaptionPanelView: () -> TGCaptionPanelView? = { return nil }
|
||||||
|
|
||||||
init(context: AccountContext, presentationData: PresentationData, controllerInteraction: WebSearchControllerInteraction, peer: EnginePeer?, chatLocation: ChatLocation?, mode: WebSearchMode, attachment: Bool) {
|
init(controller: WebSearchController, context: AccountContext, presentationData: PresentationData, controllerInteraction: WebSearchControllerInteraction, peer: EnginePeer?, chatLocation: ChatLocation?, mode: WebSearchMode, attachment: Bool) {
|
||||||
|
self.controller = controller
|
||||||
self.context = context
|
self.context = context
|
||||||
self.theme = presentationData.theme
|
self.theme = presentationData.theme
|
||||||
self.strings = presentationData.strings
|
self.strings = presentationData.strings
|
||||||
@ -187,6 +202,9 @@ class WebSearchControllerNode: ASDisplayNode {
|
|||||||
self.webSearchInterfaceState = WebSearchInterfaceState(presentationData: context.sharedContext.currentPresentationData.with { $0 })
|
self.webSearchInterfaceState = WebSearchInterfaceState(presentationData: context.sharedContext.currentPresentationData.with { $0 })
|
||||||
self.webSearchInterfaceStatePromise = ValuePromise(self.webSearchInterfaceState, ignoreRepeated: true)
|
self.webSearchInterfaceStatePromise = ValuePromise(self.webSearchInterfaceState, ignoreRepeated: true)
|
||||||
|
|
||||||
|
self.segmentedContainerNode = ASDisplayNode()
|
||||||
|
self.segmentedContainerNode.clipsToBounds = true
|
||||||
|
|
||||||
self.segmentedBackgroundNode = ASDisplayNode()
|
self.segmentedBackgroundNode = ASDisplayNode()
|
||||||
self.segmentedSeparatorNode = ASDisplayNode()
|
self.segmentedSeparatorNode = ASDisplayNode()
|
||||||
|
|
||||||
@ -225,10 +243,11 @@ class WebSearchControllerNode: ASDisplayNode {
|
|||||||
if !attachment {
|
if !attachment {
|
||||||
self.addSubnode(self.recentQueriesNode)
|
self.addSubnode(self.recentQueriesNode)
|
||||||
}
|
}
|
||||||
self.addSubnode(self.segmentedBackgroundNode)
|
self.addSubnode(self.segmentedContainerNode)
|
||||||
self.addSubnode(self.segmentedSeparatorNode)
|
self.segmentedContainerNode.addSubnode(self.segmentedBackgroundNode)
|
||||||
|
self.segmentedContainerNode.addSubnode(self.segmentedSeparatorNode)
|
||||||
if case .media = mode {
|
if case .media = mode {
|
||||||
self.addSubnode(self.segmentedControlNode)
|
self.segmentedContainerNode.addSubnode(self.segmentedControlNode)
|
||||||
}
|
}
|
||||||
if !attachment {
|
if !attachment {
|
||||||
self.addSubnode(self.toolbarBackgroundNode)
|
self.addSubnode(self.toolbarBackgroundNode)
|
||||||
@ -339,6 +358,11 @@ class WebSearchControllerNode: ASDisplayNode {
|
|||||||
self.applyPresentationData(themeUpdated: themeUpdated)
|
self.applyPresentationData(themeUpdated: themeUpdated)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateBackgroundAlpha(_ alpha: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
|
self.controller?.navigationBar?.updateBackgroundAlpha(0.0, transition: transition)
|
||||||
|
transition.updateAlpha(node: self.segmentedBackgroundNode, alpha: alpha)
|
||||||
|
}
|
||||||
|
|
||||||
func applyPresentationData(themeUpdated: Bool = true) {
|
func applyPresentationData(themeUpdated: Bool = true) {
|
||||||
self.cancelButton.setTitle(self.strings.Common_Cancel, with: Font.regular(17.0), with: self.theme.rootController.navigationBar.accentTextColor, for: .normal)
|
self.cancelButton.setTitle(self.strings.Common_Cancel, with: Font.regular(17.0), with: self.theme.rootController.navigationBar.accentTextColor, for: .normal)
|
||||||
|
|
||||||
@ -349,6 +373,7 @@ class WebSearchControllerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if themeUpdated {
|
if themeUpdated {
|
||||||
|
self.gridNode.backgroundColor = self.theme.list.plainBackgroundColor
|
||||||
self.segmentedBackgroundNode.backgroundColor = self.theme.rootController.navigationBar.opaqueBackgroundColor
|
self.segmentedBackgroundNode.backgroundColor = self.theme.rootController.navigationBar.opaqueBackgroundColor
|
||||||
self.segmentedSeparatorNode.backgroundColor = self.theme.rootController.navigationBar.separatorColor
|
self.segmentedSeparatorNode.backgroundColor = self.theme.rootController.navigationBar.separatorColor
|
||||||
self.segmentedControlNode.updateTheme(SegmentedControlTheme(theme: self.theme))
|
self.segmentedControlNode.updateTheme(SegmentedControlTheme(theme: self.theme))
|
||||||
@ -393,14 +418,19 @@ class WebSearchControllerNode: ASDisplayNode {
|
|||||||
var insets = layout.insets(options: [.input])
|
var insets = layout.insets(options: [.input])
|
||||||
insets.top += navigationBarHeight
|
insets.top += navigationBarHeight
|
||||||
|
|
||||||
|
let hasQuery = !(self.webSearchInterfaceState.state?.query ?? "").isEmpty
|
||||||
|
|
||||||
let segmentedHeight: CGFloat = self.segmentedControlNode.supernode != nil ? 44.0 : 5.0
|
let segmentedHeight: CGFloat = self.segmentedControlNode.supernode != nil ? 44.0 : 5.0
|
||||||
let panelY: CGFloat = insets.top - UIScreenPixel - 4.0
|
let panelY: CGFloat = insets.top - UIScreenPixel - 4.0
|
||||||
|
|
||||||
transition.updateFrame(node: self.segmentedBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelY), size: CGSize(width: layout.size.width, height: segmentedHeight)))
|
transition.updateSublayerTransformOffset(layer: self.segmentedContainerNode.layer, offset: CGPoint(x: 0.0, y: !hasQuery ? -44.0 : 0.0), completion: nil)
|
||||||
transition.updateFrame(node: self.segmentedSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelY + segmentedHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
transition.updateFrame(node: self.segmentedContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelY), size: CGSize(width: layout.size.width, height: segmentedHeight)))
|
||||||
|
|
||||||
|
transition.updateFrame(node: self.segmentedBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: segmentedHeight)))
|
||||||
|
transition.updateFrame(node: self.segmentedSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: segmentedHeight - UIScreenPixel), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
||||||
|
|
||||||
let controlSize = self.segmentedControlNode.updateLayout(.stretchToFill(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 10.0 * 2.0), transition: transition)
|
let controlSize = self.segmentedControlNode.updateLayout(.stretchToFill(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 10.0 * 2.0), transition: transition)
|
||||||
transition.updateFrame(node: self.segmentedControlNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((layout.size.width - layout.safeInsets.left - layout.safeInsets.right - controlSize.width) / 2.0), y: panelY + 5.0), size: controlSize))
|
transition.updateFrame(node: self.segmentedControlNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((layout.size.width - layout.safeInsets.left - layout.safeInsets.right - controlSize.width) / 2.0), y: 5.0), size: controlSize))
|
||||||
|
|
||||||
insets.top -= 4.0
|
insets.top -= 4.0
|
||||||
|
|
||||||
@ -466,7 +496,7 @@ class WebSearchControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
insets.top += segmentedHeight
|
insets.top += segmentedHeight
|
||||||
insets.bottom += toolbarHeight
|
insets.bottom += toolbarHeight
|
||||||
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: layout.size, insets: insets, preloadSize: 400.0, type: gridNodeLayoutForContainerLayout(size: layout.size, insets: insets)), transition: .immediate), itemTransition: .immediate, stationaryItems: .none,updateFirstIndexInSectionOffset: nil), completion: { _ in })
|
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: layout.size, insets: insets, preloadSize: 400.0, type: gridNodeLayoutForContainerLayout(layout)), transition: .immediate), itemTransition: .immediate, stationaryItems: .none,updateFirstIndexInSectionOffset: nil), completion: { _ in })
|
||||||
|
|
||||||
let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition)
|
let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition)
|
||||||
|
|
||||||
@ -541,7 +571,7 @@ class WebSearchControllerNode: ASDisplayNode {
|
|||||||
if self.recentQueriesNode.supernode != nil {
|
if self.recentQueriesNode.supernode != nil {
|
||||||
self.insertSubnode(gridNode, belowSubnode: self.recentQueriesNode)
|
self.insertSubnode(gridNode, belowSubnode: self.recentQueriesNode)
|
||||||
} else {
|
} else {
|
||||||
self.addSubnode(gridNode)
|
self.insertSubnode(gridNode, aboveSubnode: previousNode)
|
||||||
}
|
}
|
||||||
self.gridNode = gridNode
|
self.gridNode = gridNode
|
||||||
self.currentEntries = nil
|
self.currentEntries = nil
|
||||||
|
@ -22,7 +22,7 @@ final class WebSearchNavigationContentNode: NavigationBarContentNode {
|
|||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
|
|
||||||
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: theme, hasSeparator: false), strings: strings, fieldStyle: .modern)
|
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: theme, hasSeparator: false), strings: strings, fieldStyle: .modern, displayBackground: !attachment)
|
||||||
self.searchBar.hasCancelButton = attachment
|
self.searchBar.hasCancelButton = attachment
|
||||||
self.searchBar.placeholderString = NSAttributedString(string: attachment ? strings.Attachment_SearchWeb : strings.Common_Search, font: searchBarFont, textColor: theme.rootController.navigationSearchBar.inputPlaceholderTextColor)
|
self.searchBar.placeholderString = NSAttributedString(string: attachment ? strings.Attachment_SearchWeb : strings.Common_Search, font: searchBarFont, textColor: theme.rootController.navigationSearchBar.inputPlaceholderTextColor)
|
||||||
|
|
||||||
@ -30,13 +30,8 @@ final class WebSearchNavigationContentNode: NavigationBarContentNode {
|
|||||||
|
|
||||||
self.addSubnode(self.searchBar)
|
self.addSubnode(self.searchBar)
|
||||||
|
|
||||||
self.searchBar.textReturned = { [weak self] query in
|
|
||||||
self?.queryUpdated?(query)
|
|
||||||
}
|
|
||||||
self.searchBar.textUpdated = { [weak self] query, _ in
|
self.searchBar.textUpdated = { [weak self] query, _ in
|
||||||
if query.isEmpty {
|
self?.queryUpdated?(query)
|
||||||
self?.queryUpdated?(query)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.searchBar.cancel = { [weak self] in
|
self.searchBar.cancel = { [weak self] in
|
||||||
self?.cancel?()
|
self?.cancel?()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user