mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit '9e7107ef4e1503e120f064994319bb8f07228116'
This commit is contained in:
commit
99c6240172
@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.12</string>
|
||||
<string>5.11.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${BUILD_NUMBER}</string>
|
||||
<key>NSExtension</key>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.12</string>
|
||||
<string>5.11.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${BUILD_NUMBER}</string>
|
||||
<key>NSExtension</key>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.12</string>
|
||||
<string>5.11.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${BUILD_NUMBER}</string>
|
||||
<key>NSExtension</key>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.12</string>
|
||||
<string>5.11.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${BUILD_NUMBER}</string>
|
||||
<key>NSExtension</key>
|
||||
|
@ -185,7 +185,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.12</string>
|
||||
<string>5.11.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
@ -4744,8 +4744,11 @@ Any member of this group will be able to see messages in the channel.";
|
||||
|
||||
"ContactList.Context.SendMessage" = "Send Message";
|
||||
"ContactList.Context.StartSecretChat" = "Start Secret Chat";
|
||||
"ContactList.Context.Call" = "Cal";
|
||||
"ContactList.Context.Call" = "Call";
|
||||
|
||||
"Theme.Context.Apply" = "Apply";
|
||||
|
||||
"Settings.Context.Logout" = "Logout";
|
||||
|
||||
"Channel.EditAdmin.PermissionDeleteMessagesOfOthers" = "Delete Messages of Others";
|
||||
"Channel.AdminLog.CanDeleteMessagesOfOthers" = "Delete Messages of Others";
|
||||
|
@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.12</string>
|
||||
<string>5.11.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${BUILD_NUMBER}</string>
|
||||
<key>UIDeviceFamily</key>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.12</string>
|
||||
<string>5.11.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${BUILD_NUMBER}</string>
|
||||
<key>NSExtension</key>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.12</string>
|
||||
<string>5.11.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${BUILD_NUMBER}</string>
|
||||
<key>NSExtension</key>
|
||||
|
@ -1019,7 +1019,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
}
|
||||
|
||||
@objc private func composePressed() {
|
||||
(self.navigationController as? NavigationController)?.replaceAllButRootController(self.context.sharedContext.makeComposeController(context: self.context), animated: true)
|
||||
let controller = self.context.sharedContext.makeComposeController(context: self.context)
|
||||
self.present(controller, in: .window(.root))
|
||||
//(self.navigationController as? NavigationController)?.replaceAllButRootController(self.context.sharedContext.makeComposeController(context: self.context), animated: true)
|
||||
}
|
||||
|
||||
public func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
|
||||
|
@ -255,7 +255,7 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
private func layoutDataForConfiguration(_ layoutConfiguration: ControllerLayoutConfiguration, layout: ContainerViewLayout, index: Int) -> (CGRect, ContainerViewLayout) {
|
||||
switch layoutConfiguration {
|
||||
case .masterDetail:
|
||||
let masterWidth: CGFloat = max(320.0, floor(layout.size.width / 3.0))
|
||||
let masterWidth: CGFloat = max(320.0, min(375.0, floor(layout.size.width / 3.0)))
|
||||
let detailWidth: CGFloat = layout.size.width - masterWidth
|
||||
if index == 0 {
|
||||
return (CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: masterWidth, height: layout.size.height)), ContainerViewLayout(size: CGSize(width: masterWidth, height: layout.size.height), metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, intrinsicInsets: layout.intrinsicInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver))
|
||||
@ -358,10 +358,10 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
if let blackout = self.masterDetailsBlackout {
|
||||
let blackoutFrame: CGRect
|
||||
switch blackout {
|
||||
case .details:
|
||||
blackoutFrame = CGRect(origin: CGPoint(x: masterData.0.maxX, y: 0.0), size: lastControllerFrameAndLayout.0.size)
|
||||
case .master:
|
||||
blackoutFrame = masterData.0
|
||||
case .details:
|
||||
blackoutFrame = CGRect(origin: CGPoint(x: masterData.0.maxX, y: 0.0), size: lastControllerFrameAndLayout.0.size)
|
||||
case .master:
|
||||
blackoutFrame = masterData.0
|
||||
}
|
||||
if self.controllerView.masterDetailsBlackout == nil {
|
||||
self.controllerView.masterDetailsBlackout = ASDisplayNode()
|
||||
|
@ -37,6 +37,7 @@ public final class PresentationContext {
|
||||
weak var volumeControlStatusBarNodeView: UIView?
|
||||
|
||||
var updateIsInteractionBlocked: ((Bool) -> Void)?
|
||||
var updateHasBlocked: ((Bool) -> Void)?
|
||||
|
||||
var updateHasOpaqueOverlay: ((Bool) -> Void)?
|
||||
private(set) var hasOpaqueOverlay: Bool = false {
|
||||
@ -47,6 +48,9 @@ public final class PresentationContext {
|
||||
}
|
||||
}
|
||||
|
||||
private var modalPresentationValue: CGFloat = 0.0
|
||||
var updateModalTransition: ((CGFloat, ContainedViewLayoutTransition) -> Void)?
|
||||
|
||||
private var layout: ContainerViewLayout?
|
||||
|
||||
private var ready: Bool {
|
||||
@ -120,6 +124,20 @@ public final class PresentationContext {
|
||||
}
|
||||
}
|
||||
|
||||
private func layoutForController(containerLayout: ContainerViewLayout, controller: ContainableController) -> (ContainerViewLayout, CGRect) {
|
||||
if controller.isModalWhenInOverlay, case .regular = containerLayout.metrics.widthClass {
|
||||
let topInset = (containerLayout.statusBarHeight ?? 0.0) + 20.0
|
||||
var updatedLayout = containerLayout
|
||||
updatedLayout.statusBarHeight = nil
|
||||
updatedLayout.size = CGSize(width: min(containerLayout.size.width - 90.0, 750.0), height: min(containerLayout.size.height - 90.0, 940.0))
|
||||
updatedLayout.safeInsets = UIEdgeInsets()
|
||||
updatedLayout.intrinsicInsets = UIEdgeInsets()
|
||||
return (updatedLayout, CGRect(origin: CGPoint(x: (containerLayout.size.width - updatedLayout.size.width) / 2.0, y: (containerLayout.size.height - updatedLayout.size.height) / 2.0), size: updatedLayout.size))
|
||||
} else {
|
||||
return (containerLayout, CGRect(origin: CGPoint(), size: containerLayout.size))
|
||||
}
|
||||
}
|
||||
|
||||
public func present(_ controller: ContainableController, on level: PresentationSurfaceLevel, blockInteraction: Bool = false, completion: @escaping () -> Void) {
|
||||
let controllerReady = controller.ready.get()
|
||||
|> filter({ $0 })
|
||||
@ -140,8 +158,9 @@ public final class PresentationContext {
|
||||
controller.supportedOrientations = ViewControllerSupportedOrientations(regularSize: orientations, compactSize: orientations)
|
||||
}
|
||||
}
|
||||
controller.view.frame = CGRect(origin: CGPoint(), size: initialLayout.size)
|
||||
controller.containerLayoutUpdated(initialLayout, transition: .immediate)
|
||||
let (controllerLayout, controllerFrame) = self.layoutForController(containerLayout: initialLayout, controller: controller)
|
||||
controller.view.frame = controllerFrame
|
||||
controller.containerLayoutUpdated(controllerLayout, transition: .immediate)
|
||||
var blockInteractionToken: Int?
|
||||
if blockInteraction {
|
||||
blockInteractionToken = self.addBlockInteraction()
|
||||
@ -170,37 +189,32 @@ public final class PresentationContext {
|
||||
}
|
||||
strongSelf.controllers.insert((controller, level), at: insertIndex ?? strongSelf.controllers.count)
|
||||
if let view = strongSelf.view, let layout = strongSelf.layout {
|
||||
let (updatedControllerLayout, updatedControllerFrame) = strongSelf.layoutForController(containerLayout: layout, controller: controller)
|
||||
|
||||
(controller as? UIViewController)?.navigation_setDismiss({ [weak controller] in
|
||||
if let strongSelf = self, let controller = controller {
|
||||
strongSelf.dismiss(controller)
|
||||
}
|
||||
}, rootController: nil)
|
||||
(controller as? UIViewController)?.setIgnoreAppearanceMethodInvocations(true)
|
||||
if layout != initialLayout {
|
||||
controller.view.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
if updatedControllerLayout != controllerLayout {
|
||||
controller.view.frame = updatedControllerFrame
|
||||
if let topLevelSubview = strongSelf.topLevelSubview(for: level) {
|
||||
view.insertSubview(controller.view, belowSubview: topLevelSubview)
|
||||
} else {
|
||||
if let volumeControlStatusBarNodeView = strongSelf.volumeControlStatusBarNodeView {
|
||||
view.insertSubview(controller.view, belowSubview: volumeControlStatusBarNodeView)
|
||||
} else {
|
||||
view.addSubview(controller.view)
|
||||
}
|
||||
view.addSubview(controller.view)
|
||||
}
|
||||
controller.containerLayoutUpdated(layout, transition: .immediate)
|
||||
controller.containerLayoutUpdated(updatedControllerLayout, transition: .immediate)
|
||||
} else {
|
||||
if let topLevelSubview = strongSelf.topLevelSubview(for: level) {
|
||||
view.insertSubview(controller.view, belowSubview: topLevelSubview)
|
||||
} else {
|
||||
if let volumeControlStatusBarNodeView = strongSelf.volumeControlStatusBarNodeView {
|
||||
view.insertSubview(controller.view, belowSubview: volumeControlStatusBarNodeView)
|
||||
} else {
|
||||
view.addSubview(controller.view)
|
||||
}
|
||||
view.addSubview(controller.view)
|
||||
}
|
||||
}
|
||||
(controller as? UIViewController)?.setIgnoreAppearanceMethodInvocations(false)
|
||||
view.layer.invalidateUpTheTree()
|
||||
strongSelf.updateViews()
|
||||
controller.viewWillAppear(false)
|
||||
if let controller = controller as? PresentableController {
|
||||
controller.viewDidAppear(completion: { [weak self] in
|
||||
@ -210,8 +224,18 @@ public final class PresentationContext {
|
||||
controller.viewDidAppear(false)
|
||||
strongSelf.notifyAccessibilityScreenChanged()
|
||||
}
|
||||
|
||||
if controller.isModalWhenInOverlay, case .regular = layout.metrics.widthClass {
|
||||
let springDuration: Double = 0.52
|
||||
let springDamping: CGFloat = 110.0
|
||||
|
||||
controller.view.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: 0.0, y: layout.size.height - controllerFrame.minY)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, initialVelocity: 0.0, damping: springDamping, additive: true)
|
||||
|
||||
strongSelf.dimView?.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
strongSelf.dimView?.alpha = 1.0
|
||||
strongSelf.dimView?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
strongSelf.updateViews()
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
@ -225,12 +249,29 @@ public final class PresentationContext {
|
||||
}
|
||||
|
||||
private func dismiss(_ controller: ContainableController) {
|
||||
if let index = self.controllers.index(where: { $0.0 === controller }) {
|
||||
if let index = self.controllers.firstIndex(where: { $0.0 === controller }) {
|
||||
self.controllers.remove(at: index)
|
||||
controller.viewWillDisappear(false)
|
||||
controller.view.removeFromSuperview()
|
||||
controller.viewDidDisappear(false)
|
||||
self.updateViews()
|
||||
if controller.isModalWhenInOverlay, let layout = self.layout, case .regular = layout.metrics.widthClass {
|
||||
let (controllerLayout, controllerFrame) = self.layoutForController(containerLayout: layout, controller: controller)
|
||||
|
||||
let springDuration: Double = 0.52
|
||||
let springDamping: CGFloat = 110.0
|
||||
controller.view.layer.animateSpring(from: NSValue(cgPoint: CGPoint()), to: NSValue(cgPoint: CGPoint(x: 0.0, y: layout.size.height - controllerFrame.minY)), keyPath: "position", duration: springDuration, initialVelocity: 0.0, damping: springDamping, removeOnCompletion: false, additive: true, completion: { finished in
|
||||
controller.viewWillDisappear(false)
|
||||
controller.view.removeFromSuperview()
|
||||
controller.viewDidDisappear(false)
|
||||
self.updateViews()
|
||||
})
|
||||
} else {
|
||||
controller.viewWillDisappear(false)
|
||||
controller.view.removeFromSuperview()
|
||||
controller.viewDidDisappear(false)
|
||||
self.updateViews()
|
||||
}
|
||||
|
||||
let previousAlpha = self.dimView?.alpha ?? 0.0
|
||||
self.dimView?.alpha = 0.0
|
||||
self.dimView?.layer.animateAlpha(from: previousAlpha, to: 0.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,8 +282,11 @@ public final class PresentationContext {
|
||||
if wasReady != self.ready {
|
||||
self.readyChanged(wasReady: wasReady)
|
||||
} else if self.ready {
|
||||
self.dimView?.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
for (controller, _) in self.controllers {
|
||||
controller.containerLayoutUpdated(layout, transition: transition)
|
||||
let (controllerLayout, controllerFrame) = self.layoutForController(containerLayout: layout, controller: controller)
|
||||
controller.view.frame = controllerFrame
|
||||
controller.containerLayoutUpdated(controllerLayout, transition: transition)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -255,21 +299,31 @@ public final class PresentationContext {
|
||||
}
|
||||
}
|
||||
|
||||
var dimView: UIView?
|
||||
|
||||
private func addViews() {
|
||||
if let view = self.view, let layout = self.layout {
|
||||
let dimView: UIView
|
||||
if let currentDimView = self.dimView {
|
||||
dimView = currentDimView
|
||||
} else {
|
||||
dimView = UIView()
|
||||
dimView.alpha = 0.0
|
||||
dimView.backgroundColor = UIColor(rgb: 0x000000, alpha: 0.4)
|
||||
self.dimView = dimView
|
||||
}
|
||||
view.addSubview(dimView)
|
||||
|
||||
for (controller, _) in self.controllers {
|
||||
controller.viewWillAppear(false)
|
||||
if let topLevelSubview = self.topLevelSubview {
|
||||
view.insertSubview(controller.view, belowSubview: topLevelSubview)
|
||||
} else {
|
||||
if let volumeControlStatusBarNodeView = self.volumeControlStatusBarNodeView {
|
||||
view.insertSubview(controller.view, belowSubview: volumeControlStatusBarNodeView)
|
||||
} else {
|
||||
view.addSubview(controller.view)
|
||||
}
|
||||
view.addSubview(controller.view)
|
||||
}
|
||||
controller.view.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
controller.containerLayoutUpdated(layout, transition: .immediate)
|
||||
let (controllerLayout, controllerFrame) = self.layoutForController(containerLayout: layout, controller: controller)
|
||||
controller.view.frame = controllerFrame
|
||||
controller.containerLayoutUpdated(controllerLayout, transition: .immediate)
|
||||
if let controller = controller as? PresentableController {
|
||||
controller.viewDidAppear(completion: { [weak self] in
|
||||
self?.notifyAccessibilityScreenChanged()
|
||||
@ -291,10 +345,18 @@ public final class PresentationContext {
|
||||
}
|
||||
}
|
||||
|
||||
private weak var currentModalController: ContainableController?
|
||||
|
||||
private func updateViews() {
|
||||
self.hasOpaqueOverlay = self.currentlyBlocksBackgroundWhenInOverlay
|
||||
var modalController: ContainableController?
|
||||
var topHasOpaque = false
|
||||
for (controller, _) in self.controllers.reversed() {
|
||||
if controller.isModalWhenInOverlay {
|
||||
if modalController == nil {
|
||||
modalController = controller
|
||||
}
|
||||
}
|
||||
if topHasOpaque {
|
||||
controller.displayNode.accessibilityElementsHidden = true
|
||||
} else {
|
||||
@ -304,16 +366,51 @@ public final class PresentationContext {
|
||||
controller.displayNode.accessibilityElementsHidden = false
|
||||
}
|
||||
}
|
||||
|
||||
if self.currentModalController !== modalController {
|
||||
if let currentModalController = self.currentModalController {
|
||||
currentModalController.updateTransitionWhenPresentedAsModal = nil
|
||||
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
|
||||
currentModalController.displayNode.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner]
|
||||
}
|
||||
currentModalController.displayNode.layer.cornerRadius = 0.0
|
||||
}
|
||||
self.currentModalController = modalController
|
||||
if let modalController = modalController {
|
||||
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
|
||||
if let layout = self.layout, case .regular = layout.metrics.widthClass {
|
||||
modalController.displayNode.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner]
|
||||
} else {
|
||||
modalController.displayNode.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
|
||||
}
|
||||
}
|
||||
modalController.displayNode.layer.cornerRadius = 10.0
|
||||
modalController.updateTransitionWhenPresentedAsModal = { [weak self, weak modalController] value, transition in
|
||||
guard let strongSelf = self, let modalController = modalController, modalController === strongSelf.currentModalController else {
|
||||
return
|
||||
}
|
||||
if strongSelf.modalPresentationValue != value {
|
||||
strongSelf.modalPresentationValue = value
|
||||
strongSelf.updateModalTransition?(value, transition)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if self.modalPresentationValue != 0.0 {
|
||||
self.modalPresentationValue = 0.0
|
||||
self.updateModalTransition?(0.0, .animated(duration: 0.3, curve: .spring))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func notifyAccessibilityScreenChanged() {
|
||||
UIAccessibility.post(notification: UIAccessibility.Notification.screenChanged, argument: nil)
|
||||
}
|
||||
|
||||
func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
func hitTest(view: UIView, point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
for (controller, _) in self.controllers.reversed() {
|
||||
if controller.isViewLoaded {
|
||||
if let result = controller.view.hitTest(point, with: event) {
|
||||
if let result = controller.view.hitTest(view.convert(point, to: controller.view), with: event) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +155,6 @@ private func checkIsPreviewingView(_ view: UIView) -> Bool {
|
||||
private func applyThemeToPreviewingView(_ view: UIView, accentColor: UIColor, darkBlur: Bool) {
|
||||
if let previewingActionGroupClass = previewingActionGroupClass, view.isKind(of: previewingActionGroupClass) {
|
||||
view.tintColor = accentColor
|
||||
testZoomBlurEffect((view.superview?.superview?.subviews[1] as? UIVisualEffectView)?.effect)
|
||||
if darkBlur {
|
||||
applyThemeToPreviewingEffectView(view)
|
||||
}
|
||||
@ -665,7 +664,7 @@ public class Window1 {
|
||||
}
|
||||
}
|
||||
|
||||
if let result = self.presentationContext.hitTest(point, with: event) {
|
||||
if let result = self.presentationContext.hitTest(view: self.hostView.containerView, point: point, with: event) {
|
||||
return result
|
||||
}
|
||||
return self.viewController?.view.hitTest(point, with: event)
|
||||
|
@ -415,9 +415,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
func setMessage(_ message: Message) {
|
||||
self.currentMessage = message
|
||||
|
||||
self.actionButton.isHidden = message.containsSecretMedia || Namespaces.Message.allScheduled.contains(message.id.namespace)
|
||||
|
||||
let canDelete: Bool
|
||||
var canShare = !message.containsSecretMedia && !Namespaces.Message.allScheduled.contains(message.id.namespace)
|
||||
if let peer = message.peers[message.id.peerId] {
|
||||
if peer is TelegramUser || peer is TelegramSecretChat {
|
||||
canDelete = true
|
||||
@ -434,6 +433,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
}
|
||||
} else {
|
||||
canDelete = false
|
||||
canShare = false
|
||||
}
|
||||
|
||||
var authorNameText: String?
|
||||
@ -466,7 +466,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
messageText = galleryCaptionStringWithAppliedEntities(message.text, entities: entities)
|
||||
}
|
||||
|
||||
if self.currentMessageText != messageText || canDelete != !self.deleteButton.isHidden || self.currentAuthorNameText != authorNameText || self.currentDateText != dateText {
|
||||
self.actionButton.isHidden = message.containsSecretMedia || Namespaces.Message.allScheduled.contains(message.id.namespace)
|
||||
|
||||
|
||||
if self.currentMessageText != messageText || canDelete != !self.deleteButton.isHidden || canShare != !self.actionButton.isHidden || self.currentAuthorNameText != authorNameText || self.currentDateText != dateText {
|
||||
self.currentMessageText = messageText
|
||||
|
||||
if messageText.length == 0 {
|
||||
@ -485,6 +488,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
self.dateNode.attributedText = NSAttributedString(string: dateText, font: dateFont, textColor: .white)
|
||||
|
||||
self.deleteButton.isHidden = !canDelete
|
||||
self.actionButton.isHidden = !canShare
|
||||
|
||||
self.requestLayout?(.immediate)
|
||||
}
|
||||
|
@ -402,7 +402,7 @@ public class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
||||
|
||||
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.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight))
|
||||
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight))
|
||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight))
|
||||
}
|
||||
|
||||
|
@ -124,7 +124,7 @@ private func readPacketCallback(userData: UnsafeMutableRawPointer?, buffer: Unsa
|
||||
let readingOffset = context.readingOffset
|
||||
let readCount = max(0, min(fileSize - readingOffset, Int(bufferSize)))
|
||||
let range = readingOffset ..< (readingOffset + readCount)
|
||||
precondition(readCount < 1 * 1024 * 1024)
|
||||
assert(readCount < 16 * 1024 * 1024)
|
||||
|
||||
lseek(fd, off_t(range.lowerBound), SEEK_SET)
|
||||
var data = Data(count: readCount)
|
||||
@ -147,7 +147,7 @@ private func readPacketCallback(userData: UnsafeMutableRawPointer?, buffer: Unsa
|
||||
let readCount = max(0, min(next.size - readingOffset, Int(bufferSize)))
|
||||
let range = readingOffset ..< (readingOffset + readCount)
|
||||
|
||||
precondition(readCount < 1 * 1024 * 1024)
|
||||
assert(readCount < 16 * 1024 * 1024)
|
||||
|
||||
let fd = open(next.path, O_RDONLY, S_IRUSR)
|
||||
if fd >= 0 {
|
||||
|
@ -461,7 +461,7 @@ private func stringForRight(strings: PresentationStrings, right: TelegramChatAdm
|
||||
} else if right.contains(.canEditMessages) {
|
||||
return strings.Channel_EditAdmin_PermissionEditMessages
|
||||
} else if right.contains(.canDeleteMessages) {
|
||||
return strings.Channel_EditAdmin_PermissionDeleteMessages
|
||||
return isGroup ? strings.Channel_EditAdmin_PermissionDeleteMessages : strings.Channel_EditAdmin_PermissionDeleteMessagesOfOthers
|
||||
} else if right.contains(.canBanUsers) {
|
||||
return strings.Channel_EditAdmin_PermissionBanUsers
|
||||
} else if right.contains(.canInviteUsers) {
|
||||
|
@ -380,7 +380,7 @@ private func channelAdminsControllerEntries(presentationData: PresentationData,
|
||||
switch participant.participant {
|
||||
case .creator:
|
||||
canEdit = false
|
||||
canOpen = false
|
||||
canOpen = isGroup && peer.flags.contains(.isCreator)
|
||||
case let .member(id, _, adminInfo, _, _):
|
||||
if id == accountPeerId {
|
||||
canEdit = false
|
||||
|
@ -718,7 +718,7 @@ public final class MessageHistoryView {
|
||||
for entry in state.entries {
|
||||
if mutableView.namespaces.contains(entry.message.id.namespace) {
|
||||
let read: Bool
|
||||
if !entry.message.flags.intersection(.IsIncomingMask).isEmpty {
|
||||
if entry.message.flags.contains(.Incoming) {
|
||||
read = false
|
||||
} else if let readState = states[entry.message.id.peerId] {
|
||||
read = readState.isOutgoingMessageIndexRead(entry.message.index)
|
||||
|
@ -50,6 +50,8 @@ public final class ThemePreviewController: ViewController {
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationTheme: self.previewTheme, presentationStrings: self.presentationData.strings))
|
||||
|
||||
self.isModalWhenInOverlay = true
|
||||
|
||||
let themeName: String
|
||||
if case let .theme(theme) = source {
|
||||
themeName = theme.title
|
||||
@ -239,7 +241,7 @@ public final class ThemePreviewController: ViewController {
|
||||
return telegramThemes(postbox: context.account.postbox, network: context.account.network, accountManager: context.sharedContext.accountManager)
|
||||
|> take(1)
|
||||
|> mapToSignal { themes -> Signal<PresentationThemeReference, NoError> in
|
||||
let similarTheme = themes.filter { $0.isCreator && $0.title == info.title }.first
|
||||
let similarTheme = themes.first(where: { $0.isCreator && $0.title == info.title })
|
||||
if let similarTheme = similarTheme {
|
||||
return updateTheme(account: context.account, accountManager: context.sharedContext.accountManager, theme: similarTheme, title: nil, slug: nil, resource: info.resource, thumbnailData: themeThumbnailData)
|
||||
|> map(Optional.init)
|
||||
|
@ -45,6 +45,8 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
private var chatNodes: [ListViewItemNode]?
|
||||
private let maskNode: ASImageNode
|
||||
|
||||
private let separatorNode: ASDisplayNode
|
||||
|
||||
private let chatContainerNode: ASDisplayNode
|
||||
private let instantChatBackgroundNode: WallpaperBackgroundNode
|
||||
private let remoteChatBackgroundNode: TransformImageNode
|
||||
@ -113,6 +115,9 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
self.maskNode.displayWithoutProcessing = true
|
||||
self.maskNode.contentMode = .scaleToFill
|
||||
|
||||
self.separatorNode = ASDisplayNode()
|
||||
self.separatorNode.backgroundColor = previewTheme.rootController.tabBar.separatorColor
|
||||
|
||||
super.init()
|
||||
|
||||
self.setViewBlock({
|
||||
@ -145,6 +150,8 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
self.chatContainerNode.addSubnode(self.instantChatBackgroundNode)
|
||||
self.chatContainerNode.addSubnode(self.remoteChatBackgroundNode)
|
||||
|
||||
self.addSubnode(self.separatorNode)
|
||||
|
||||
self.toolbarNode.cancel = {
|
||||
dismiss()
|
||||
}
|
||||
@ -299,13 +306,19 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
|
||||
func animateIn(completion: (() -> Void)? = nil) {
|
||||
self.layer.animatePosition(from: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), to: self.layer.position, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
if let (layout, _) = self.validLayout, case .compact = layout.metrics.widthClass {
|
||||
self.layer.animatePosition(from: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), to: self.layer.position, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
}
|
||||
}
|
||||
|
||||
func animateOut(completion: (() -> Void)? = nil) {
|
||||
self.layer.animatePosition(from: self.layer.position, to: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), duration: 0.2, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, completion: { _ in
|
||||
if let (layout, _) = self.validLayout, case .compact = layout.metrics.widthClass {
|
||||
self.layer.animatePosition(from: self.layer.position, to: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), duration: 0.2, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, completion: { _ in
|
||||
completion?()
|
||||
})
|
||||
} else {
|
||||
completion?()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private func updateChatsLayout(layout: ContainerViewLayout, topInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
@ -350,14 +363,21 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
|
||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer7.id, namespace: 0, id: 0), timestamp: timestamp - 420)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer7.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp - 420, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer6, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_7_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer7), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||
|
||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
|
||||
let width: CGFloat
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
width = layout.size.width / 2.0
|
||||
} else {
|
||||
width = layout.size.width
|
||||
}
|
||||
|
||||
let params = ListViewItemLayoutParams(width: width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
|
||||
if let chatNodes = self.chatNodes {
|
||||
for i in 0 ..< items.count {
|
||||
let itemNode = chatNodes[i]
|
||||
items[i].updateNode(async: { $0() }, node: {
|
||||
return itemNode
|
||||
}, params: params, previousItem: i == 0 ? nil : items[i - 1], nextItem: i == (items.count - 1) ? nil : items[i + 1], animation: .None, completion: { (layout, apply) in
|
||||
let nodeFrame = CGRect(origin: itemNode.frame.origin, size: CGSize(width: layout.size.width, height: layout.size.height))
|
||||
let nodeFrame = CGRect(origin: itemNode.frame.origin, size: CGSize(width: width, height: layout.size.height))
|
||||
|
||||
itemNode.contentSize = layout.contentSize
|
||||
itemNode.insets = layout.insets
|
||||
@ -419,14 +439,21 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
let message4 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message4, theme: self.previewTheme, strings: self.presentationData.strings, wallpaper: self.previewTheme.chat.defaultWallpaper, fontSize: self.presentationData.fontSize, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil))
|
||||
|
||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
|
||||
let width: CGFloat
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
width = layout.size.width / 2.0
|
||||
} else {
|
||||
width = layout.size.width
|
||||
}
|
||||
|
||||
let params = ListViewItemLayoutParams(width: width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
|
||||
if let messageNodes = self.messageNodes {
|
||||
for i in 0 ..< items.count {
|
||||
let itemNode = messageNodes[i]
|
||||
items[i].updateNode(async: { $0() }, node: {
|
||||
return itemNode
|
||||
}, params: params, previousItem: i == 0 ? nil : items[i - 1], nextItem: i == (items.count - 1) ? nil : items[i + 1], animation: .None, completion: { (layout, apply) in
|
||||
let nodeFrame = CGRect(origin: itemNode.frame.origin, size: CGSize(width: layout.size.width, height: layout.size.height))
|
||||
let nodeFrame = CGRect(origin: itemNode.frame.origin, size: CGSize(width: width, height: layout.size.height))
|
||||
|
||||
itemNode.contentSize = layout.contentSize
|
||||
itemNode.insets = layout.insets
|
||||
@ -463,23 +490,49 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (layout, navigationBarHeight)
|
||||
|
||||
let bounds = CGRect(origin: CGPoint(), size: layout.size)
|
||||
self.scrollNode.frame = bounds
|
||||
|
||||
let toolbarHeight = 49.0 + layout.intrinsicInsets.bottom
|
||||
self.chatListBackgroundNode.frame = CGRect(x: bounds.width, y: 0.0, width: bounds.width, height: bounds.height)
|
||||
self.chatContainerNode.frame = CGRect(x: 0.0, y: 0.0, width: bounds.width, height: bounds.height)
|
||||
|
||||
let bottomInset: CGFloat
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
self.chatListBackgroundNode.frame = CGRect(x: 0.0, y: 0.0, width: bounds.width / 2.0, height: bounds.height)
|
||||
self.chatContainerNode.frame = CGRect(x: bounds.width / 2.0, y: 0.0, width: bounds.width / 2.0, height: bounds.height)
|
||||
self.scrollNode.view.contentSize = CGSize(width: bounds.width, height: bounds.height)
|
||||
|
||||
self.pageControlNode.isHidden = true
|
||||
self.pageControlBackgroundNode.isHidden = true
|
||||
self.separatorNode.isHidden = false
|
||||
|
||||
self.separatorNode.frame = CGRect(x: bounds.width / 2.0, y: 0.0, width: UIScreenPixel, height: bounds.height - toolbarHeight)
|
||||
|
||||
bottomInset = 0.0
|
||||
} else {
|
||||
self.chatListBackgroundNode.frame = CGRect(x: bounds.width, y: 0.0, width: bounds.width, height: bounds.height)
|
||||
self.chatContainerNode.frame = CGRect(x: 0.0, y: 0.0, width: bounds.width, height: bounds.height)
|
||||
self.scrollNode.view.contentSize = CGSize(width: bounds.width * 2.0, height: bounds.height)
|
||||
|
||||
self.pageControlNode.isHidden = false
|
||||
self.pageControlBackgroundNode.isHidden = false
|
||||
self.separatorNode.isHidden = true
|
||||
|
||||
bottomInset = 66.0
|
||||
}
|
||||
|
||||
self.instantChatBackgroundNode.frame = self.chatContainerNode.bounds
|
||||
self.remoteChatBackgroundNode.frame = self.chatContainerNode.bounds
|
||||
self.blurredNode.frame = self.chatContainerNode.bounds
|
||||
|
||||
self.scrollNode.view.contentSize = CGSize(width: bounds.width * 2.0, height: bounds.height)
|
||||
|
||||
transition.updateFrame(node: self.toolbarNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - toolbarHeight), size: CGSize(width: layout.size.width, height: 49.0 + layout.intrinsicInsets.bottom)))
|
||||
self.toolbarNode.updateLayout(size: CGSize(width: layout.size.width, height: 49.0), layout: layout, transition: transition)
|
||||
|
||||
self.updateChatsLayout(layout: layout, topInset: navigationBarHeight, transition: transition)
|
||||
self.updateMessagesLayout(layout: layout, bottomInset: self.isPreview ? 0.0 : (toolbarHeight + 66.0), transition: transition)
|
||||
self.updateMessagesLayout(layout: layout, bottomInset: self.isPreview ? 0.0 : (toolbarHeight + bottomInset), transition: transition)
|
||||
|
||||
let pageControlSize = self.pageControlNode.measure(CGSize(width: bounds.width, height: 100.0))
|
||||
let pageControlFrame = CGRect(origin: CGPoint(x: floor((bounds.width - pageControlSize.width) / 2.0), y: layout.size.height - toolbarHeight - 42.0), size: pageControlSize)
|
||||
|
@ -576,7 +576,7 @@ public func actualizedTheme(account: Account, accountManager: AccountManager, th
|
||||
}
|
||||
}
|
||||
|> map { themes -> TelegramTheme in
|
||||
let updatedTheme = themes.filter { $0.id == theme.id }.first
|
||||
let updatedTheme = themes.first(where: { $0.id == theme.id })
|
||||
if let updatedTheme = updatedTheme {
|
||||
if !areThemesEqual(updatedTheme, currentTheme) {
|
||||
currentTheme = updatedTheme
|
||||
|
@ -120,7 +120,7 @@ private func makeDefaultDayPresentationTheme(accentColor: UIColor, serviceBackgr
|
||||
itemDestructiveColor: destructiveColor,
|
||||
itemPlaceholderTextColor: UIColor(rgb: 0xc8c8ce),
|
||||
itemBlocksBackgroundColor: .white,
|
||||
itemHighlightedBackgroundColor: UIColor(rgb: 0xd9d9d9),
|
||||
itemHighlightedBackgroundColor: UIColor(rgb: 0xe5e5ea),
|
||||
itemBlocksSeparatorColor: UIColor(rgb: 0xc8c7cc),
|
||||
itemPlainSeparatorColor: UIColor(rgb: 0xc8c7cc),
|
||||
disclosureArrowColor: UIColor(rgb: 0xbab9be),
|
||||
@ -163,7 +163,7 @@ private func makeDefaultDayPresentationTheme(accentColor: UIColor, serviceBackgr
|
||||
itemSeparatorColor: UIColor(rgb: 0xc8c7cc),
|
||||
itemBackgroundColor: .white,
|
||||
pinnedItemBackgroundColor: UIColor(rgb: 0xf7f7f7),
|
||||
itemHighlightedBackgroundColor: UIColor(rgb: 0xd9d9d9),
|
||||
itemHighlightedBackgroundColor: UIColor(rgb: 0xe5e5ea),
|
||||
itemSelectedBackgroundColor: UIColor(rgb: 0xe9f0fa),
|
||||
titleColor: .black,
|
||||
secretTitleColor: secretColor,
|
||||
|
@ -520,6 +520,10 @@ public func updatedPresentationData(accountManager: AccountManager, applicationI
|
||||
switch effectiveChatWallpaper {
|
||||
case .builtin, .color:
|
||||
effectiveChatWallpaper = themeValue.chat.defaultWallpaper
|
||||
case let .file(file):
|
||||
if file.isPattern {
|
||||
effectiveChatWallpaper = themeValue.chat.defaultWallpaper
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -484,7 +484,7 @@ final class SharedApplicationContext {
|
||||
return UIApplication.shared.open(parsedUrl, options: [UIApplication.OpenExternalURLOptionsKey.universalLinksOnly: true as NSNumber], completionHandler: { value in
|
||||
completion.completion(value)
|
||||
})
|
||||
} else if let escapedUrl = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let parsedUrl = URL(string: escapedUrl) {
|
||||
} else if let escapedUrl = (url.removingPercentEncoding ?? url).addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let parsedUrl = URL(string: escapedUrl) {
|
||||
return UIApplication.shared.open(parsedUrl, options: [UIApplication.OpenExternalURLOptionsKey.universalLinksOnly: true as NSNumber], completionHandler: { value in
|
||||
completion.completion(value)
|
||||
})
|
||||
|
@ -1585,7 +1585,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
|
||||
func sendButtonFrame() -> CGRect? {
|
||||
if let frame = self.textInputPanelNode?.actionButtons.frame {
|
||||
if let mediaPreviewNode = self.inputPanelNode as? ChatRecordingPreviewInputPanelNode {
|
||||
return mediaPreviewNode.convert(mediaPreviewNode.sendButton.frame, to: self)
|
||||
} else if let frame = self.textInputPanelNode?.actionButtons.frame {
|
||||
return self.textInputPanelNode?.convert(frame, to: self)
|
||||
} else {
|
||||
return nil
|
||||
|
@ -44,7 +44,7 @@ class ChatHoleItemNode: ListViewItemNode {
|
||||
let backgroundNode: ASImageNode
|
||||
let labelNode: TextNode
|
||||
|
||||
private let layoutConstants = ChatMessageItemLayoutConstants()
|
||||
private let layoutConstants = ChatMessageItemLayoutConstants.default
|
||||
|
||||
init() {
|
||||
self.backgroundNode = ASImageNode()
|
||||
|
@ -36,7 +36,7 @@ private func canEditMessage(accountPeerId: PeerId, limitsConfiguration: LimitsCo
|
||||
if let peer = message.peers[message.id.peerId], let channel = peer as? TelegramChannel {
|
||||
switch channel.info {
|
||||
case .broadcast:
|
||||
if message.author?.id == message.id.peerId || channel.hasPermission(.editAllMessages) {
|
||||
if channel.hasPermission(.editAllMessages) || !message.flags.contains(.Incoming) {
|
||||
hasEditRights = true
|
||||
}
|
||||
default:
|
||||
@ -53,7 +53,7 @@ private func canEditMessage(accountPeerId: PeerId, limitsConfiguration: LimitsCo
|
||||
if let peer = peer as? TelegramChannel {
|
||||
switch peer.info {
|
||||
case .broadcast:
|
||||
if peer.hasPermission(.editAllMessages) {
|
||||
if peer.hasPermission(.editAllMessages) || !message.flags.contains(.Incoming) {
|
||||
hasEditRights = true
|
||||
}
|
||||
case .group:
|
||||
|
@ -339,6 +339,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
let currentItem = self.item
|
||||
|
||||
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
|
||||
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params)
|
||||
let incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
||||
var imageSize: CGSize = CGSize(width: 200.0, height: 200.0)
|
||||
var isEmoji = false
|
||||
|
@ -590,6 +590,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
let weakSelf = Weak(self)
|
||||
|
||||
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
|
||||
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params)
|
||||
return ChatMessageBubbleItemNode.beginLayout(selfReference: weakSelf, item, params, mergedTop, mergedBottom, dateHeaderAtBottom,
|
||||
currentContentClassesPropertiesAndLayouts: currentContentClassesPropertiesAndLayouts,
|
||||
authorNameLayout: authorNameLayout,
|
||||
|
@ -113,6 +113,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
||||
let currentForwardInfo = self.appliedForwardInfo
|
||||
|
||||
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
|
||||
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params)
|
||||
let incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
||||
|
||||
let avatarInset: CGFloat
|
||||
|
@ -78,17 +78,40 @@ struct ChatMessageItemLayoutConstants {
|
||||
let instantVideo: ChatMessageItemInstantVideoConstants
|
||||
let wallpapers: ChatMessageItemWallpaperLayoutConstants
|
||||
|
||||
init() {
|
||||
self.avatarDiameter = 37.0
|
||||
self.timestampHeaderHeight = 34.0
|
||||
static var `default`: ChatMessageItemLayoutConstants {
|
||||
return self.compact
|
||||
}
|
||||
|
||||
fileprivate static var compact: ChatMessageItemLayoutConstants {
|
||||
let bubble = ChatMessageItemBubbleLayoutConstants(edgeInset: 4.0, defaultSpacing: 2.0 + UIScreenPixel, mergedSpacing: 1.0, maximumWidthFill: ChatMessageItemWidthFill(compactInset: 36.0, compactWidthBoundary: 500.0, freeMaximumFillFactor: 0.85), minimumSize: CGSize(width: 40.0, height: 35.0), contentInsets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 0.0), borderInset: UIScreenPixel, strokeInsets: UIEdgeInsets(top: 1.0 - UIScreenPixel, left: 1.0 - UIScreenPixel, bottom: 1.0 - UIScreenPixel, right: 1.0 - UIScreenPixel))
|
||||
let text = ChatMessageItemTextLayoutConstants(bubbleInsets: UIEdgeInsets(top: 6.0 + UIScreenPixel, left: 12.0, bottom: 6.0 - UIScreenPixel, right: 12.0))
|
||||
let image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 1.0 + UIScreenPixel, left: 1.0 + UIScreenPixel, bottom: 1.0 + UIScreenPixel, right: 1.0 + UIScreenPixel), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 17.0, mergedCornerRadius: 5.0, contentMergedCornerRadius: 5.0, maxDimensions: CGSize(width: 300.0, height: 300.0), minDimensions: CGSize(width: 170.0, height: 74.0))
|
||||
let video = ChatMessageItemVideoLayoutConstants(maxHorizontalHeight: 250.0, maxVerticalHeight: 360.0)
|
||||
let file = ChatMessageItemFileLayoutConstants(bubbleInsets: UIEdgeInsets(top: 15.0, left: 9.0, bottom: 15.0, right: 12.0))
|
||||
let instantVideo = ChatMessageItemInstantVideoConstants(insets: UIEdgeInsets(top: 4.0, left: 0.0, bottom: 4.0, right: 0.0), dimensions: CGSize(width: 212.0, height: 212.0))
|
||||
let wallpapers = ChatMessageItemWallpaperLayoutConstants(maxTextWidth: 180.0)
|
||||
|
||||
self.bubble = ChatMessageItemBubbleLayoutConstants(edgeInset: 4.0, defaultSpacing: 2.0 + UIScreenPixel, mergedSpacing: 1.0, maximumWidthFill: ChatMessageItemWidthFill(compactInset: 36.0, compactWidthBoundary: 500.0, freeMaximumFillFactor: 0.85), minimumSize: CGSize(width: 40.0, height: 35.0), contentInsets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 0.0), borderInset: UIScreenPixel, strokeInsets: UIEdgeInsets(top: 1.0 - UIScreenPixel, left: 1.0 - UIScreenPixel, bottom: 1.0 - UIScreenPixel, right: 1.0 - UIScreenPixel))
|
||||
self.text = ChatMessageItemTextLayoutConstants(bubbleInsets: UIEdgeInsets(top: 6.0 + UIScreenPixel, left: 12.0, bottom: 6.0 - UIScreenPixel, right: 12.0))
|
||||
self.image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 1.0 + UIScreenPixel, left: 1.0 + UIScreenPixel, bottom: 1.0 + UIScreenPixel, right: 1.0 + UIScreenPixel), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 17.0, mergedCornerRadius: 5.0, contentMergedCornerRadius: 5.0, maxDimensions: CGSize(width: 300.0, height: 300.0), minDimensions: CGSize(width: 170.0, height: 74.0))
|
||||
self.video = ChatMessageItemVideoLayoutConstants(maxHorizontalHeight: 250.0, maxVerticalHeight: 360.0)
|
||||
self.file = ChatMessageItemFileLayoutConstants(bubbleInsets: UIEdgeInsets(top: 15.0, left: 9.0, bottom: 15.0, right: 12.0))
|
||||
self.instantVideo = ChatMessageItemInstantVideoConstants(insets: UIEdgeInsets(top: 4.0, left: 0.0, bottom: 4.0, right: 0.0), dimensions: CGSize(width: 212.0, height: 212.0))
|
||||
self.wallpapers = ChatMessageItemWallpaperLayoutConstants(maxTextWidth: 180.0)
|
||||
return ChatMessageItemLayoutConstants(avatarDiameter: 37.0, timestampHeaderHeight: 34.0, bubble: bubble, image: image, video: video, text: text, file: file, instantVideo: instantVideo, wallpapers: wallpapers)
|
||||
}
|
||||
|
||||
fileprivate static var regular: ChatMessageItemLayoutConstants {
|
||||
let bubble = ChatMessageItemBubbleLayoutConstants(edgeInset: 4.0, defaultSpacing: 2.0 + UIScreenPixel, mergedSpacing: 1.0, maximumWidthFill: ChatMessageItemWidthFill(compactInset: 36.0, compactWidthBoundary: 500.0, freeMaximumFillFactor: 0.65), minimumSize: CGSize(width: 40.0, height: 35.0), contentInsets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 0.0), borderInset: UIScreenPixel, strokeInsets: UIEdgeInsets(top: 1.0 - UIScreenPixel, left: 1.0 - UIScreenPixel, bottom: 1.0 - UIScreenPixel, right: 1.0 - UIScreenPixel))
|
||||
let text = ChatMessageItemTextLayoutConstants(bubbleInsets: UIEdgeInsets(top: 6.0 + UIScreenPixel, left: 12.0, bottom: 6.0 - UIScreenPixel, right: 12.0))
|
||||
let image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 1.0 + UIScreenPixel, left: 1.0 + UIScreenPixel, bottom: 1.0 + UIScreenPixel, right: 1.0 + UIScreenPixel), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 17.0, mergedCornerRadius: 5.0, contentMergedCornerRadius: 5.0, maxDimensions: CGSize(width: 440.0, height: 440.0), minDimensions: CGSize(width: 170.0, height: 74.0))
|
||||
let video = ChatMessageItemVideoLayoutConstants(maxHorizontalHeight: 250.0, maxVerticalHeight: 360.0)
|
||||
let file = ChatMessageItemFileLayoutConstants(bubbleInsets: UIEdgeInsets(top: 15.0, left: 9.0, bottom: 15.0, right: 12.0))
|
||||
let instantVideo = ChatMessageItemInstantVideoConstants(insets: UIEdgeInsets(top: 4.0, left: 0.0, bottom: 4.0, right: 0.0), dimensions: CGSize(width: 212.0, height: 212.0))
|
||||
let wallpapers = ChatMessageItemWallpaperLayoutConstants(maxTextWidth: 180.0)
|
||||
|
||||
return ChatMessageItemLayoutConstants(avatarDiameter: 37.0, timestampHeaderHeight: 34.0, bubble: bubble, image: image, video: video, text: text, file: file, instantVideo: instantVideo, wallpapers: wallpapers)
|
||||
}
|
||||
}
|
||||
|
||||
func chatMessageItemLayoutConstants(_ constants: (ChatMessageItemLayoutConstants, ChatMessageItemLayoutConstants), params: ListViewItemLayoutParams) -> ChatMessageItemLayoutConstants {
|
||||
if params.width > 680.0 {
|
||||
return constants.1
|
||||
} else {
|
||||
return constants.0
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,8 +120,6 @@ enum ChatMessageItemBottomNeighbor {
|
||||
case merged(semi: Bool)
|
||||
}
|
||||
|
||||
let defaultChatMessageItemLayoutConstants = ChatMessageItemLayoutConstants()
|
||||
|
||||
enum ChatMessagePeekPreviewContent {
|
||||
case media(Media)
|
||||
case url(ASDisplayNode, CGRect, String, Bool)
|
||||
@ -607,7 +628,7 @@ final class ChatMessageAccessibilityData {
|
||||
}
|
||||
|
||||
public class ChatMessageItemView: ListViewItemNode {
|
||||
let layoutConstants = defaultChatMessageItemLayoutConstants
|
||||
let layoutConstants = (ChatMessageItemLayoutConstants.compact, ChatMessageItemLayoutConstants.regular)
|
||||
|
||||
var item: ChatMessageItem?
|
||||
var accessibilityData: ChatMessageAccessibilityData?
|
||||
|
@ -141,6 +141,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
let currentItem = self.item
|
||||
|
||||
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
|
||||
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params)
|
||||
let incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
||||
var imageSize: CGSize = CGSize(width: 100.0, height: 100.0)
|
||||
if let telegramFile = telegramFile {
|
||||
|
@ -670,7 +670,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
order = [
|
||||
(.canChangeInfo, self.presentationData.strings.Channel_AdminLog_CanChangeInfo),
|
||||
(.canPostMessages, self.presentationData.strings.Channel_AdminLog_CanSendMessages),
|
||||
(.canDeleteMessages, self.presentationData.strings.Channel_AdminLog_CanDeleteMessages),
|
||||
(.canDeleteMessages, self.presentationData.strings.Channel_AdminLog_CanDeleteMessagesOfOthers),
|
||||
(.canEditMessages, self.presentationData.strings.Channel_AdminLog_CanEditMessages),
|
||||
(.canInviteUsers, self.presentationData.strings.Channel_AdminLog_CanInviteUsers),
|
||||
(.canPinMessages, self.presentationData.strings.Channel_AdminLog_CanPinMessages),
|
||||
|
@ -19,7 +19,7 @@ private func generatePlayIcon(_ theme: PresentationTheme) -> UIImage? {
|
||||
|
||||
final class ChatRecordingPreviewInputPanelNode: ChatInputPanelNode {
|
||||
private let deleteButton: HighlightableButtonNode
|
||||
private let sendButton: HighlightableButtonNode
|
||||
let sendButton: HighlightTrackingButtonNode
|
||||
private var sendButtonRadialStatusNode: ChatSendButtonRadialStatusNode?
|
||||
private let playButton: HighlightableButtonNode
|
||||
private let pauseButton: HighlightableButtonNode
|
||||
@ -42,7 +42,7 @@ final class ChatRecordingPreviewInputPanelNode: ChatInputPanelNode {
|
||||
self.deleteButton.displaysAsynchronously = false
|
||||
self.deleteButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: theme.chat.inputPanel.panelControlAccentColor), for: [])
|
||||
|
||||
self.sendButton = HighlightableButtonNode()
|
||||
self.sendButton = HighlightTrackingButtonNode()
|
||||
self.sendButton.displaysAsynchronously = false
|
||||
self.sendButton.setImage(PresentationResourcesChat.chatInputPanelSendButtonImage(theme), for: [])
|
||||
|
||||
@ -87,6 +87,16 @@ final class ChatRecordingPreviewInputPanelNode: ChatInputPanelNode {
|
||||
self.addSubnode(self.durationLabel)
|
||||
self.addSubnode(self.waveformButton)
|
||||
|
||||
self.sendButton.highligthedChanged = { [weak self] highlighted in
|
||||
if let strongSelf = self {
|
||||
if highlighted {
|
||||
strongSelf.sendButton.layer.animateScale(from: 1.0, to: 0.75, duration: 0.4, removeOnCompletion: false)
|
||||
} else if let presentationLayer = strongSelf.sendButton.layer.presentation() {
|
||||
strongSelf.sendButton.layer.animateScale(from: CGFloat((presentationLayer.value(forKeyPath: "transform.scale.y") as? NSNumber)?.floatValue ?? 1.0), to: 1.0, duration: 0.25, removeOnCompletion: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.deleteButton.addTarget(self, action: #selector(self.deletePressed), forControlEvents: [.touchUpInside])
|
||||
self.sendButton.addTarget(self, action: #selector(self.sendPressed), forControlEvents: [.touchUpInside])
|
||||
|
||||
@ -98,8 +108,18 @@ final class ChatRecordingPreviewInputPanelNode: ChatInputPanelNode {
|
||||
self.statusDisposable.dispose()
|
||||
}
|
||||
|
||||
@objc func buttonPressed() {
|
||||
self.interfaceInteraction?.deleteChat()
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
let gestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.handleLongPress(_:)))
|
||||
gestureRecognizer.minimumPressDuration = 0.4
|
||||
self.sendButton.view.addGestureRecognizer(gestureRecognizer)
|
||||
}
|
||||
|
||||
@objc func handleLongPress(_ gestureRecognizer: UILongPressGestureRecognizer) {
|
||||
if gestureRecognizer.state == .began {
|
||||
self.interfaceInteraction?.displaySendMessageOptions()
|
||||
}
|
||||
}
|
||||
|
||||
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, maxHeight: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
|
||||
|
@ -61,7 +61,7 @@ class ChatUnreadItemNode: ListViewItemNode {
|
||||
|
||||
private var theme: ChatPresentationThemeData?
|
||||
|
||||
private let layoutConstants = ChatMessageItemLayoutConstants()
|
||||
private let layoutConstants = ChatMessageItemLayoutConstants.default
|
||||
|
||||
init() {
|
||||
self.backgroundNode = ASImageNode()
|
||||
|
@ -44,7 +44,11 @@ public class ComposeController: ViewController {
|
||||
|
||||
self.title = self.presentationData.strings.Compose_NewMessage
|
||||
|
||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||
self.isModalWhenInOverlay = true
|
||||
|
||||
//self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(cancelPressed))
|
||||
|
||||
self.scrollToTop = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
@ -257,4 +261,8 @@ public class ComposeController: ViewController {
|
||||
private func openPeer(peerId: PeerId) {
|
||||
(self.navigationController as? NavigationController)?.replaceTopController(ChatControllerImpl(context: self.context, chatLocation: .peer(peerId)), animated: true)
|
||||
}
|
||||
|
||||
@objc private func cancelPressed() {
|
||||
self.presentingViewController?.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
subscriber.putError(.generic)
|
||||
subscriber.putError(.unsupported)
|
||||
}
|
||||
|
||||
return disposables
|
||||
|
Binary file not shown.
@ -414,6 +414,6 @@ final class VerticalListContextResultsChatInputPanelItemNode: ListViewItemNode {
|
||||
guard let item = self.item else {
|
||||
return
|
||||
}
|
||||
item.resultSelected(item.result, self, self.bounds)
|
||||
let _ = item.resultSelected(item.result, self, self.bounds)
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,7 @@
|
||||
NSData *jsonData = [[NSData alloc] initWithContentsOfFile:filePath];
|
||||
NSDictionary *JSONObject = jsonData ? [NSJSONSerialization JSONObjectWithData:jsonData
|
||||
options:0 error:&error] : nil;
|
||||
if (JSONObject && !error) {
|
||||
if (JSONObject && [JSONObject isKindOfClass:[NSDictionary class]] && !error) {
|
||||
LOTComposition *laScene = [[self alloc] initWithJSON:JSONObject withAssetBundle:[NSBundle mainBundle]];
|
||||
laScene.rootDirectory = [filePath stringByDeletingLastPathComponent];
|
||||
[[LOTAnimationCache sharedCache] addAnimation:laScene forKey:animationName];
|
||||
|
Loading…
x
Reference in New Issue
Block a user