mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 09:20:08 +00:00
ipad fixes
This commit is contained in:
parent
bb94bd7e88
commit
10e3733a88
@ -10,21 +10,38 @@ import DisplayPrivate
|
||||
public final class NavigationControllerTheme {
|
||||
public let navigationBar: NavigationBarTheme
|
||||
public let emptyAreaColor: UIColor
|
||||
public let emptyDetailIcon: UIImage?
|
||||
|
||||
public init(navigationBar: NavigationBarTheme, emptyAreaColor: UIColor, emptyDetailIcon: UIImage?) {
|
||||
public init(navigationBar: NavigationBarTheme, emptyAreaColor: UIColor) {
|
||||
self.navigationBar = navigationBar
|
||||
self.emptyAreaColor = emptyAreaColor
|
||||
self.emptyDetailIcon = emptyDetailIcon
|
||||
}
|
||||
}
|
||||
|
||||
public struct NavigationAnimationOptions : OptionSet {
|
||||
public let rawValue: Int
|
||||
|
||||
public init(rawValue: Int) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
|
||||
public init() {
|
||||
self.rawValue = 0
|
||||
}
|
||||
|
||||
public static let removeOnMasterDetails = NavigationAnimationOptions(rawValue: 1 << 0)
|
||||
}
|
||||
|
||||
private final class NavigationControllerContainerView: UIView {
|
||||
override class var layerClass: AnyClass {
|
||||
return CATracingLayer.self
|
||||
}
|
||||
}
|
||||
|
||||
public enum NavigationEmptyDetailsBackgoundMode {
|
||||
case image(UIImage)
|
||||
case wallpaper(UIImage)
|
||||
}
|
||||
|
||||
private final class NavigationControllerView: UITracingLayerView {
|
||||
var inTransition = false
|
||||
|
||||
@ -34,7 +51,8 @@ private final class NavigationControllerView: UITracingLayerView {
|
||||
var navigationBackgroundView: UIView?
|
||||
var navigationSeparatorView: UIView?
|
||||
var emptyDetailView: UIImageView?
|
||||
|
||||
var detailsBackground: WallpaperbackgroundNode?
|
||||
var masterDetailsBlackout: ASDisplayNode?
|
||||
var topControllerNode: ASDisplayNode?
|
||||
|
||||
/*override var accessibilityElements: [Any]? {
|
||||
@ -98,12 +116,20 @@ public enum NavigationControllerMode {
|
||||
case automaticMasterDetail
|
||||
}
|
||||
|
||||
public enum MasterDetailLayoutBlackout : Equatable {
|
||||
case master
|
||||
case details
|
||||
}
|
||||
|
||||
open class NavigationController: UINavigationController, ContainableController, UIGestureRecognizerDelegate {
|
||||
public var isOpaqueWhenInOverlay: Bool = true
|
||||
public var blocksBackgroundWhenInOverlay: Bool = true
|
||||
|
||||
public var ready: Promise<Bool> = Promise(true)
|
||||
|
||||
private var masterDetailsBlackout: MasterDetailLayoutBlackout?
|
||||
private var backgroundDetailsMode: NavigationEmptyDetailsBackgoundMode?
|
||||
|
||||
public var lockOrientation: Bool = false
|
||||
|
||||
public var deferScreenEdgeGestures: UIRectEdge = UIRectEdge()
|
||||
@ -150,10 +176,23 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
return self._displayNode!
|
||||
}
|
||||
|
||||
public init(mode: NavigationControllerMode, theme: NavigationControllerTheme) {
|
||||
public func updateMasterDetailsBlackout(_ blackout: MasterDetailLayoutBlackout?, transition: ContainedViewLayoutTransition) {
|
||||
self.masterDetailsBlackout = blackout
|
||||
if isViewLoaded {
|
||||
self.view.endEditing(true)
|
||||
}
|
||||
self.requestLayout(transition: transition)
|
||||
}
|
||||
public func updateBackgroundDetailsMode(_ mode: NavigationEmptyDetailsBackgoundMode?, transition: ContainedViewLayoutTransition) {
|
||||
self.backgroundDetailsMode = mode
|
||||
self.requestLayout(transition: transition)
|
||||
}
|
||||
|
||||
|
||||
public init(mode: NavigationControllerMode, theme: NavigationControllerTheme, backgroundDetailsMode: NavigationEmptyDetailsBackgoundMode? = nil) {
|
||||
self.mode = mode
|
||||
self.theme = theme
|
||||
|
||||
self.backgroundDetailsMode = backgroundDetailsMode
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
@ -195,12 +234,12 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
self.controllerView.separatorView.backgroundColor = theme.navigationBar.separatorColor
|
||||
self.controllerView.navigationBackgroundView?.backgroundColor = theme.navigationBar.backgroundColor
|
||||
self.controllerView.navigationSeparatorView?.backgroundColor = theme.navigationBar.separatorColor
|
||||
if let emptyDetailView = self.controllerView.emptyDetailView {
|
||||
emptyDetailView.image = theme.emptyDetailIcon
|
||||
if let image = theme.emptyDetailIcon {
|
||||
emptyDetailView.frame = CGRect(origin: CGPoint(x: floor(emptyDetailView.center.x - image.size.width / 2.0), y: floor(emptyDetailView.center.y - image.size.height / 2.0)), size: image.size)
|
||||
}
|
||||
}
|
||||
// if let emptyDetailView = self.controllerView.emptyDetailView {
|
||||
// emptyDetailView.image = theme.emptyDetailIcon
|
||||
// if let image = theme.emptyDetailIcon {
|
||||
// emptyDetailView.frame = CGRect(origin: CGPoint(x: floor(emptyDetailView.center.x - image.size.width / 2.0), y: floor(emptyDetailView.center.y - image.size.height / 2.0)), size: image.size)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@ -256,41 +295,137 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
|
||||
let navigationBackgroundFrame = CGRect(origin: CGPoint(x: masterData.0.maxX, y: 0.0), size: CGSize(width: lastControllerFrameAndLayout.0.width, height: (layout.statusBarHeight ?? 0.0) + 44.0))
|
||||
|
||||
if let navigationBackgroundView = self.controllerView.navigationBackgroundView, let navigationSeparatorView = self.controllerView.navigationSeparatorView, let emptyDetailView = self.controllerView.emptyDetailView {
|
||||
transition.updateFrame(view: navigationBackgroundView, frame: navigationBackgroundFrame)
|
||||
transition.updateFrame(view: navigationSeparatorView, frame: CGRect(origin: CGPoint(x: navigationBackgroundFrame.minX, y: navigationBackgroundFrame.maxY), size: CGSize(width: navigationBackgroundFrame.width, height: UIScreenPixel)))
|
||||
if let image = emptyDetailView.image {
|
||||
transition.updateFrame(view: emptyDetailView, frame: CGRect(origin: CGPoint(x: masterData.0.maxX + floor((lastControllerFrameAndLayout.0.size.width - image.size.width) / 2.0), y: floor((lastControllerFrameAndLayout.0.size.height - image.size.height) / 2.0)), size: image.size))
|
||||
if let backgroundDetailsMode = self.backgroundDetailsMode {
|
||||
|
||||
switch backgroundDetailsMode {
|
||||
case let .image(image):
|
||||
if let detailsBackground = self.controllerView.detailsBackground {
|
||||
self.controllerView.detailsBackground = nil
|
||||
transition.updateAlpha(node: detailsBackground, alpha: 0.0, completion: { [weak detailsBackground] _ in
|
||||
detailsBackground?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
let emptyDetailView: UIImageView
|
||||
if let emptyView = self.controllerView.emptyDetailView {
|
||||
emptyDetailView = emptyView
|
||||
} else {
|
||||
let navigationBackgroundView = UIView()
|
||||
navigationBackgroundView.backgroundColor = self.theme.navigationBar.backgroundColor
|
||||
let navigationSeparatorView = UIView()
|
||||
navigationSeparatorView.backgroundColor = self.theme.navigationBar.separatorColor
|
||||
let emptyDetailView = UIImageView()
|
||||
emptyDetailView.image = self.theme.emptyDetailIcon
|
||||
emptyDetailView = UIImageView()
|
||||
emptyDetailView.alpha = 0.0
|
||||
|
||||
self.controllerView.navigationBackgroundView = navigationBackgroundView
|
||||
self.controllerView.navigationSeparatorView = navigationSeparatorView
|
||||
self.controllerView.emptyDetailView = emptyDetailView
|
||||
|
||||
self.controllerView.insertSubview(navigationBackgroundView, at: 0)
|
||||
self.controllerView.insertSubview(navigationSeparatorView, at: 1)
|
||||
self.controllerView.insertSubview(emptyDetailView, at: 2)
|
||||
|
||||
navigationBackgroundView.frame = navigationBackgroundFrame
|
||||
navigationSeparatorView.frame = CGRect(origin: CGPoint(x: navigationBackgroundFrame.minX, y: navigationBackgroundFrame.maxY), size: CGSize(width: navigationBackgroundFrame.width, height: UIScreenPixel))
|
||||
|
||||
transition.animatePositionAdditive(layer: navigationBackgroundView.layer, offset: CGPoint(x: navigationBackgroundFrame.width, y: 0.0))
|
||||
transition.animatePositionAdditive(layer: navigationSeparatorView.layer, offset: CGPoint(x: navigationBackgroundFrame.width, y: 0.0))
|
||||
|
||||
if let image = emptyDetailView.image {
|
||||
emptyDetailView.frame = CGRect(origin: CGPoint(x: masterData.0.maxX + floor((lastControllerFrameAndLayout.0.size.width - image.size.width) / 2.0), y: floor((lastControllerFrameAndLayout.0.size.height - image.size.height) / 2.0)), size: image.size)
|
||||
}
|
||||
|
||||
emptyDetailView.image = image
|
||||
if emptyDetailView.superview == nil {
|
||||
self.controllerView.insertSubview(emptyDetailView, at: 0)
|
||||
}
|
||||
transition.updateAlpha(layer: emptyDetailView.layer, alpha: 1.0)
|
||||
|
||||
emptyDetailView.frame = CGRect(origin: CGPoint(x: masterData.0.maxX + floor((lastControllerFrameAndLayout.0.size.width - image.size.width) / 2.0), y: floor((lastControllerFrameAndLayout.0.size.height - image.size.height) / 2.0)), size: image.size)
|
||||
|
||||
|
||||
case let .wallpaper(image):
|
||||
if let emptyDetailView = self.controllerView.emptyDetailView {
|
||||
self.controllerView.emptyDetailView = nil
|
||||
transition.updateAlpha(layer: emptyDetailView.layer, alpha: 0.0, completion: { [weak emptyDetailView] _ in
|
||||
emptyDetailView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
let detailsBackground: WallpaperbackgroundNode
|
||||
if let background = self.controllerView.detailsBackground {
|
||||
detailsBackground = background
|
||||
} else {
|
||||
detailsBackground = WallpaperbackgroundNode()
|
||||
detailsBackground.alpha = 0.0
|
||||
self.controllerView.detailsBackground = detailsBackground
|
||||
}
|
||||
detailsBackground.image = image
|
||||
if detailsBackground.supernode == nil {
|
||||
self.controllerView.insertSubview(detailsBackground.view, at: 0)
|
||||
}
|
||||
transition.updateAlpha(node: detailsBackground, alpha: 1.0)
|
||||
detailsBackground.frame = CGRect(origin: CGPoint(x: masterData.0.maxX, y: 0.0), size: lastControllerFrameAndLayout.0.size)
|
||||
}
|
||||
|
||||
} else {
|
||||
if let emptyDetailView = self.controllerView.emptyDetailView {
|
||||
self.controllerView.emptyDetailView = nil
|
||||
transition.updateAlpha(layer: emptyDetailView.layer, alpha: 0.0, completion: { [weak emptyDetailView] _ in
|
||||
emptyDetailView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
if let detailsBackground = self.controllerView.detailsBackground {
|
||||
self.controllerView.detailsBackground = nil
|
||||
transition.updateAlpha(node: detailsBackground, alpha: 0.0, completion: { [weak detailsBackground] _ in
|
||||
detailsBackground?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if let emptyDetailView = self.controllerView.emptyDetailView {
|
||||
// transition.updateFrame(view: navigationBackgroundView, frame: navigationBackgroundFrame)
|
||||
// transition.updateFrame(view: navigationSeparatorView, frame: CGRect(origin: CGPoint(x: navigationBackgroundFrame.minX, y: navigationBackgroundFrame.maxY), size: CGSize(width: navigationBackgroundFrame.width, height: UIScreenPixel)))
|
||||
// if let image = emptyDetailView.image {
|
||||
// transition.updateFrame(view: emptyDetailView, frame: CGRect(origin: CGPoint(x: masterData.0.maxX + floor((lastControllerFrameAndLayout.0.size.width - image.size.width) / 2.0), y: floor((lastControllerFrameAndLayout.0.size.height - image.size.height) / 2.0)), size: image.size))
|
||||
// }
|
||||
} else {
|
||||
// let navigationBackgroundView = UIView()
|
||||
// navigationBackgroundView.backgroundColor = self.theme.navigationBar.c
|
||||
// let navigationSeparatorView = UIView()
|
||||
// navigationSeparatorView.backgroundColor = self.theme.navigationBar.separatorColor
|
||||
// let emptyDetailView = UIImageView()
|
||||
// emptyDetailView.image = self.theme.emptyDetailIcon
|
||||
// emptyDetailView.alpha = 0.0
|
||||
//
|
||||
// self.controllerView.navigationBackgroundView = navigationBackgroundView
|
||||
// self.controllerView.navigationSeparatorView = navigationSeparatorView
|
||||
// self.controllerView.emptyDetailView = emptyDetailView
|
||||
//
|
||||
// self.controllerView.insertSubview(navigationBackgroundView, at: 0)
|
||||
// self.controllerView.insertSubview(navigationSeparatorView, at: 1)
|
||||
// self.controllerView.insertSubview(emptyDetailView, at: 0)
|
||||
|
||||
// navigationBackgroundView.frame = navigationBackgroundFrame
|
||||
// navigationSeparatorView.frame = CGRect(origin: CGPoint(x: navigationBackgroundFrame.minX, y: navigationBackgroundFrame.maxY), size: CGSize(width: navigationBackgroundFrame.width, height: UIScreenPixel))
|
||||
//
|
||||
// transition.animatePositionAdditive(layer: navigationBackgroundView.layer, offset: CGPoint(x: navigationBackgroundFrame.width, y: 0.0))
|
||||
// transition.animatePositionAdditive(layer: navigationSeparatorView.layer, offset: CGPoint(x: navigationBackgroundFrame.width, y: 0.0))
|
||||
|
||||
// if let image = emptyDetailView.image {
|
||||
// emptyDetailView.frame = CGRect(origin: CGPoint(x: masterData.0.maxX + floor((lastControllerFrameAndLayout.0.size.width - image.size.width) / 2.0), y: floor((lastControllerFrameAndLayout.0.size.height - image.size.height) / 2.0)), size: image.size)
|
||||
// }
|
||||
//
|
||||
// transition.updateAlpha(layer: emptyDetailView.layer, alpha: 1.0)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
if self.controllerView.masterDetailsBlackout == nil {
|
||||
self.controllerView.masterDetailsBlackout = ASDisplayNode()
|
||||
self.controllerView.masterDetailsBlackout?.backgroundColor = UIColor.black
|
||||
self.controllerView.masterDetailsBlackout?.alpha = 0
|
||||
self.controllerView.masterDetailsBlackout?.frame = blackoutFrame
|
||||
}
|
||||
let blackoutNode = self.controllerView.masterDetailsBlackout!
|
||||
if blackoutNode.supernode == nil {
|
||||
self.controllerView.addSubnode(blackoutNode)
|
||||
}
|
||||
transition.updateFrame(node: blackoutNode, frame: blackoutFrame)
|
||||
transition.updateAlpha(node: blackoutNode, alpha: 0.2)
|
||||
} else {
|
||||
if let blackout = self.controllerView.masterDetailsBlackout {
|
||||
self.controllerView.masterDetailsBlackout = nil
|
||||
transition.updateAlpha(node: blackout, alpha: 0.0, completion: { [weak blackout] _ in
|
||||
blackout?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
transition.updateFrame(view: self.controllerView.separatorView, frame: CGRect(origin: CGPoint(x: masterData.0.maxX, y: 0.0), size: CGSize(width: UIScreenPixel, height: layout.size.height)))
|
||||
case .single:
|
||||
self.viewControllers.first?.view.clipsToBounds = false
|
||||
@ -310,6 +445,12 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
emptyDetailView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
if let blackout = self.controllerView.masterDetailsBlackout {
|
||||
self.controllerView.masterDetailsBlackout = nil
|
||||
transition.updateAlpha(node: blackout, alpha: 0.0, completion: { [weak blackout] _ in
|
||||
blackout?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
}
|
||||
self.controllerView.containerView.clipsToBounds = false
|
||||
lastControllerFrameAndLayout = layoutDataForConfiguration(layoutConfiguration, layout: layout, index: 1)
|
||||
@ -348,6 +489,11 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
} else {
|
||||
controller.navigationBar?.previousItem = .item(viewControllers[i - 1].navigationItem)
|
||||
}
|
||||
if i < self._viewControllers.count - 1 {
|
||||
controller.navigationCustomData = (viewControllers[i + 1] as? ViewController)?.customData
|
||||
} else {
|
||||
controller.navigationCustomData = nil
|
||||
}
|
||||
}
|
||||
viewControllers[i].navigation_setNavigationController(self)
|
||||
|
||||
@ -872,15 +1018,26 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
}
|
||||
}
|
||||
|
||||
public func replaceControllersAndPush(controllers: [UIViewController], controller: ViewController, animated: Bool, ready: ValuePromise<Bool>? = nil, completion: @escaping () -> Void = {}) {
|
||||
public func replaceControllersAndPush(controllers: [UIViewController], controller: ViewController, animated: Bool, options: NavigationAnimationOptions = [], ready: ValuePromise<Bool>? = nil, completion: @escaping () -> Void = {}) {
|
||||
self.view.endEditing(true)
|
||||
var animated = animated
|
||||
|
||||
self.scheduleAfterLayout { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if let validLayout = strongSelf.validLayout {
|
||||
var (_, controllerLayout) = strongSelf.layoutDataForConfiguration(strongSelf.layoutConfiguration(for: validLayout), layout: validLayout, index: strongSelf.viewControllers.count)
|
||||
let configuration = strongSelf.layoutConfiguration(for: validLayout)
|
||||
var (_, controllerLayout) = strongSelf.layoutDataForConfiguration(configuration, layout: validLayout, index: strongSelf.viewControllers.count)
|
||||
controllerLayout.inputHeight = nil
|
||||
if options.contains(.removeOnMasterDetails) {
|
||||
switch configuration {
|
||||
case .masterDetail:
|
||||
animated = false
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
controller.containerLayoutUpdated(controllerLayout, transition: .immediate)
|
||||
}
|
||||
strongSelf.currentPushDisposable.set((controller.ready.get()
|
||||
@ -898,16 +1055,26 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
}
|
||||
}
|
||||
|
||||
public func replaceAllButRootController(_ controller: ViewController, animated: Bool, ready: ValuePromise<Bool>? = nil, completion: @escaping () -> Void = {}) {
|
||||
public func replaceAllButRootController(_ controller: ViewController, animated: Bool, animationOptions: NavigationAnimationOptions = [], ready: ValuePromise<Bool>? = nil, completion: @escaping () -> Void = {}) {
|
||||
self.view.endEditing(true)
|
||||
self.scheduleAfterLayout { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var animated = animated
|
||||
if let validLayout = strongSelf.validLayout {
|
||||
var (_, controllerLayout) = strongSelf.layoutDataForConfiguration(strongSelf.layoutConfiguration(for: validLayout), layout: validLayout, index: strongSelf.viewControllers.count)
|
||||
let configuration = strongSelf.layoutConfiguration(for: validLayout)
|
||||
var (_, controllerLayout) = strongSelf.layoutDataForConfiguration(configuration, layout: validLayout, index: strongSelf.viewControllers.count)
|
||||
controllerLayout.inputHeight = nil
|
||||
controller.containerLayoutUpdated(controllerLayout, transition: .immediate)
|
||||
switch configuration {
|
||||
case .masterDetail:
|
||||
if animationOptions.contains(.removeOnMasterDetails) {
|
||||
animated = false
|
||||
}
|
||||
case .single:
|
||||
break
|
||||
}
|
||||
}
|
||||
strongSelf.currentPushDisposable.set((controller.ready.get()
|
||||
|> deliverOnMainQueue
|
||||
|
||||
@ -73,6 +73,14 @@ open class TabBarController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
open override var navigationCustomData: Any? {
|
||||
didSet {
|
||||
for controller in controllers {
|
||||
controller.navigationCustomData = navigationCustomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public private(set) var controllers: [ViewController] = []
|
||||
|
||||
private let _ready = Promise<Bool>()
|
||||
|
||||
@ -206,6 +206,13 @@ open class ViewControllerPresentationArguments {
|
||||
public var scrollToTopWithTabBar: (() -> Void)?
|
||||
public var longTapWithTabBar: (() -> Void)?
|
||||
|
||||
open var navigationCustomData: Any?
|
||||
open var customData: Any? {
|
||||
get {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public var attemptNavigation: (@escaping () -> Void) -> Bool = { _ in
|
||||
return true
|
||||
}
|
||||
|
||||
73
submodules/Display/Display/WallpaperBackgroundNode.swift
Normal file
73
submodules/Display/Display/WallpaperBackgroundNode.swift
Normal file
@ -0,0 +1,73 @@
|
||||
//
|
||||
// WallpaperBackgroundNode.swift
|
||||
// Display
|
||||
//
|
||||
// Created by Mikhail Filimonov on 13/06/2019.
|
||||
// Copyright © 2019 Telegram. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
private let motionAmount: CGFloat = 32.0
|
||||
|
||||
public final class WallpaperbackgroundNode: ASDisplayNode {
|
||||
let contentNode: ASDisplayNode
|
||||
|
||||
public var motionEnabled: Bool = false {
|
||||
didSet {
|
||||
if oldValue != self.motionEnabled {
|
||||
if self.motionEnabled {
|
||||
let horizontal = UIInterpolatingMotionEffect(keyPath: "center.x", type: .tiltAlongHorizontalAxis)
|
||||
horizontal.minimumRelativeValue = motionAmount
|
||||
horizontal.maximumRelativeValue = -motionAmount
|
||||
|
||||
let vertical = UIInterpolatingMotionEffect(keyPath: "center.y", type: .tiltAlongVerticalAxis)
|
||||
vertical.minimumRelativeValue = motionAmount
|
||||
vertical.maximumRelativeValue = -motionAmount
|
||||
|
||||
let group = UIMotionEffectGroup()
|
||||
group.motionEffects = [horizontal, vertical]
|
||||
self.contentNode.view.addMotionEffect(group)
|
||||
} else {
|
||||
for effect in self.contentNode.view.motionEffects {
|
||||
self.contentNode.view.removeMotionEffect(effect)
|
||||
}
|
||||
}
|
||||
self.updateScale()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var image: UIImage? {
|
||||
didSet {
|
||||
self.contentNode.contents = self.image?.cgImage
|
||||
}
|
||||
}
|
||||
|
||||
func updateScale() {
|
||||
if self.motionEnabled {
|
||||
let scale = (self.frame.width + motionAmount * 2.0) / self.frame.width
|
||||
self.contentNode.transform = CATransform3DMakeScale(scale, scale, 1.0)
|
||||
} else {
|
||||
self.contentNode.transform = CATransform3DIdentity
|
||||
}
|
||||
}
|
||||
|
||||
public override init() {
|
||||
self.contentNode = ASDisplayNode()
|
||||
self.contentNode.contentMode = .scaleAspectFill
|
||||
|
||||
super.init()
|
||||
|
||||
self.clipsToBounds = true
|
||||
self.contentNode.frame = self.bounds
|
||||
self.addSubnode(self.contentNode)
|
||||
}
|
||||
|
||||
override public func layout() {
|
||||
super.layout()
|
||||
self.contentNode.bounds = self.bounds
|
||||
self.contentNode.position = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
|
||||
self.updateScale()
|
||||
}
|
||||
}
|
||||
@ -23,6 +23,7 @@
|
||||
D015F7581D1B467200E269B5 /* ActionSheetController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D015F7571D1B467200E269B5 /* ActionSheetController.swift */; };
|
||||
D015F75A1D1B46B600E269B5 /* ActionSheetControllerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D015F7591D1B46B600E269B5 /* ActionSheetControllerNode.swift */; };
|
||||
D01847661FFA72E000075256 /* ContainedViewLayoutTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01847651FFA72E000075256 /* ContainedViewLayoutTransition.swift */; };
|
||||
D01E1F0222B28D9400AD6DAE /* WallpaperBackgroundNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01E1F0122B28D9400AD6DAE /* WallpaperBackgroundNode.swift */; };
|
||||
D01E2BDE1D9049620066BF65 /* GridNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01E2BDD1D9049620066BF65 /* GridNode.swift */; };
|
||||
D01E2BE01D90498E0066BF65 /* GridNodeScroller.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01E2BDF1D90498E0066BF65 /* GridNodeScroller.swift */; };
|
||||
D01E2BE21D9049F60066BF65 /* GridItemNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01E2BE11D9049F60066BF65 /* GridItemNode.swift */; };
|
||||
@ -195,6 +196,7 @@
|
||||
D015F7591D1B46B600E269B5 /* ActionSheetControllerNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetControllerNode.swift; sourceTree = "<group>"; };
|
||||
D01847651FFA72E000075256 /* ContainedViewLayoutTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainedViewLayoutTransition.swift; sourceTree = "<group>"; };
|
||||
D01C06C61FC2558F001561AB /* SwiftSignalKitMac.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SwiftSignalKitMac.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D01E1F0122B28D9400AD6DAE /* WallpaperBackgroundNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WallpaperBackgroundNode.swift; sourceTree = "<group>"; };
|
||||
D01E2BDD1D9049620066BF65 /* GridNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GridNode.swift; sourceTree = "<group>"; };
|
||||
D01E2BDF1D90498E0066BF65 /* GridNodeScroller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GridNodeScroller.swift; sourceTree = "<group>"; };
|
||||
D01E2BE11D9049F60066BF65 /* GridItemNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GridItemNode.swift; sourceTree = "<group>"; };
|
||||
@ -462,6 +464,7 @@
|
||||
D0CA3F892073F7650042D2B6 /* LinkHighlightingNode.swift */,
|
||||
D04554A921BDB93E007A6DD9 /* CollectionIndexNode.swift */,
|
||||
09DD88EA21BCA5E0000766BC /* EditableTextNode.swift */,
|
||||
D01E1F0122B28D9400AD6DAE /* WallpaperBackgroundNode.swift */,
|
||||
);
|
||||
name = Nodes;
|
||||
sourceTree = "<group>";
|
||||
@ -939,6 +942,7 @@
|
||||
D033874E223D3E86007A2CE4 /* AccessibilityAreaNode.swift in Sources */,
|
||||
D015F75A1D1B46B600E269B5 /* ActionSheetControllerNode.swift in Sources */,
|
||||
D01847661FFA72E000075256 /* ContainedViewLayoutTransition.swift in Sources */,
|
||||
D01E1F0222B28D9400AD6DAE /* WallpaperBackgroundNode.swift in Sources */,
|
||||
D03725C11D6DF594007FC290 /* ContextMenuNode.swift in Sources */,
|
||||
D03AA4DB202DA6D60056C405 /* PeekControllerContent.swift in Sources */,
|
||||
D053CB611D22B4F200DD41DF /* CATracingLayer.m in Sources */,
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "DetailLogoBlank@2x.png",
|
||||
"filename" : "EmptyChat@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 7.6 KiB |
BIN
submodules/TelegramUI/Images.xcassets/Chat List/EmptyMasterDetailIcon.imageset/EmptyChat@2x.png
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Chat List/EmptyMasterDetailIcon.imageset/EmptyChat@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
@ -47,7 +47,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
self.theme = theme
|
||||
self.openUrl = openUrl
|
||||
|
||||
super.init(mode: .single, theme: NavigationControllerTheme(navigationBar: AuthorizationSequenceController.navigationBarTheme(theme), emptyAreaColor: .black, emptyDetailIcon: nil))
|
||||
super.init(mode: .single, theme: NavigationControllerTheme(navigationBar: AuthorizationSequenceController.navigationBarTheme(theme), emptyAreaColor: .black))
|
||||
|
||||
self.stateDisposable = (account.postbox.stateView()
|
||||
|> map { view -> InnerState in
|
||||
|
||||
@ -227,6 +227,10 @@ public final class ChatController: TelegramController, GalleryHiddenMediaTarget,
|
||||
|
||||
var purposefulAction: (() -> Void)?
|
||||
|
||||
public override var customData: Any? {
|
||||
return self.chatLocation
|
||||
}
|
||||
|
||||
public init(context: AccountContext, chatLocation: ChatLocation, messageId: MessageId? = nil, botStart: ChatControllerInitialBotStart? = nil, mode: ChatControllerPresentationMode = .standard(previewing: false)) {
|
||||
let _ = ChatControllerCount.modify { value in
|
||||
return value + 1
|
||||
@ -4164,6 +4168,7 @@ public final class ChatController: TelegramController, GalleryHiddenMediaTarget,
|
||||
if updatedChatPresentationInterfaceState.interfaceState.selectionState != controllerInteraction.selectionState {
|
||||
controllerInteraction.selectionState = updatedChatPresentationInterfaceState.interfaceState.selectionState
|
||||
self.updateItemNodesSelectionStates(animated: transition.isAnimated)
|
||||
(self.navigationController as? NavigationController)?.updateMasterDetailsBlackout(controllerInteraction.selectionState != nil ? .master : nil, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
@ -5369,6 +5374,8 @@ public final class ChatController: TelegramController, GalleryHiddenMediaTarget,
|
||||
self.chatDisplayNode.historyNode.scrollToEndOfHistory()
|
||||
}
|
||||
|
||||
|
||||
|
||||
public func navigateToMessage(messageLocation: NavigateToMessageLocation, animated: Bool, forceInCurrentChat: Bool = false, completion: (() -> Void)? = nil, customPresentProgress: ((ViewController, Any?) -> Void)? = nil) {
|
||||
self.navigateToMessage(from: nil, to: messageLocation, rememberInStack: false, forceInCurrentChat: forceInCurrentChat, animated: animated, completion: completion, customPresentProgress: customPresentProgress)
|
||||
}
|
||||
|
||||
@ -6,69 +6,6 @@ import Display
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
|
||||
private let motionAmount: CGFloat = 32.0
|
||||
|
||||
final class ChatBackgroundNode: ASDisplayNode {
|
||||
let contentNode: ASDisplayNode
|
||||
|
||||
var motionEnabled: Bool = false {
|
||||
didSet {
|
||||
if oldValue != self.motionEnabled {
|
||||
if self.motionEnabled {
|
||||
let horizontal = UIInterpolatingMotionEffect(keyPath: "center.x", type: .tiltAlongHorizontalAxis)
|
||||
horizontal.minimumRelativeValue = motionAmount
|
||||
horizontal.maximumRelativeValue = -motionAmount
|
||||
|
||||
let vertical = UIInterpolatingMotionEffect(keyPath: "center.y", type: .tiltAlongVerticalAxis)
|
||||
vertical.minimumRelativeValue = motionAmount
|
||||
vertical.maximumRelativeValue = -motionAmount
|
||||
|
||||
let group = UIMotionEffectGroup()
|
||||
group.motionEffects = [horizontal, vertical]
|
||||
self.contentNode.view.addMotionEffect(group)
|
||||
} else {
|
||||
for effect in self.contentNode.view.motionEffects {
|
||||
self.contentNode.view.removeMotionEffect(effect)
|
||||
}
|
||||
}
|
||||
self.updateScale()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var image: UIImage? {
|
||||
didSet {
|
||||
self.contentNode.contents = self.image?.cgImage
|
||||
}
|
||||
}
|
||||
|
||||
func updateScale() {
|
||||
if self.motionEnabled {
|
||||
let scale = (self.frame.width + motionAmount * 2.0) / self.frame.width
|
||||
self.contentNode.transform = CATransform3DMakeScale(scale, scale, 1.0)
|
||||
} else {
|
||||
self.contentNode.transform = CATransform3DIdentity
|
||||
}
|
||||
}
|
||||
|
||||
override init() {
|
||||
self.contentNode = ASDisplayNode()
|
||||
self.contentNode.contentMode = .scaleAspectFill
|
||||
|
||||
super.init()
|
||||
|
||||
self.clipsToBounds = true
|
||||
self.contentNode.frame = self.bounds
|
||||
self.addSubnode(self.contentNode)
|
||||
}
|
||||
|
||||
override func layout() {
|
||||
super.layout()
|
||||
self.contentNode.bounds = self.bounds
|
||||
self.contentNode.position = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
|
||||
self.updateScale()
|
||||
}
|
||||
}
|
||||
|
||||
private var backgroundImageForWallpaper: (TelegramWallpaper, Bool, UIImage)?
|
||||
private var serviceBackgroundColorForWallpaper: (TelegramWallpaper, UIColor)?
|
||||
|
||||
@ -69,7 +69,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
let backgroundNode: ChatBackgroundNode
|
||||
let backgroundNode: WallpaperbackgroundNode
|
||||
let historyNode: ChatHistoryListNode
|
||||
let historyNodeContainer: ASDisplayNode
|
||||
let loadingNode: ChatLoadingNode
|
||||
@ -191,7 +191,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
self.navigationBar = navigationBar
|
||||
self.controller = controller
|
||||
|
||||
self.backgroundNode = ChatBackgroundNode()
|
||||
self.backgroundNode = WallpaperbackgroundNode()
|
||||
self.backgroundNode.displaysAsynchronously = false
|
||||
|
||||
self.titleAccessoryPanelContainer = ChatControllerTitlePanelNodeContainer()
|
||||
|
||||
@ -94,6 +94,12 @@ public class ChatListController: TelegramController, UIViewControllerPreviewingD
|
||||
|
||||
private var searchContentNode: NavigationBarSearchContentNode?
|
||||
|
||||
public override var navigationCustomData: Any? {
|
||||
didSet {
|
||||
self.chatListDisplayNode.chatListNode.updateSelectedChatLocation(self.navigationCustomData as? ChatLocation, progress: 1, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
public init(context: AccountContext, groupId: PeerGroupId, controlsHistoryPreload: Bool, hideNetworkActivityStatus: Bool = false) {
|
||||
self.context = context
|
||||
self.controlsHistoryPreload = controlsHistoryPreload
|
||||
@ -684,9 +690,7 @@ public class ChatListController: TelegramController, UIViewControllerPreviewingD
|
||||
scrollToEndIfExists = true
|
||||
}
|
||||
|
||||
let animated: Bool = !scrollToEndIfExists || strongSelf.groupId != PeerGroupId.root
|
||||
|
||||
navigateToChatController(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), scrollToEndIfExists: animated, animated: animated, parentGroupId: strongSelf.groupId, completion: { [weak self] in
|
||||
navigateToChatController(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), scrollToEndIfExists: scrollToEndIfExists, options: strongSelf.groupId == PeerGroupId.root ? [.removeOnMasterDetails] : [], parentGroupId: strongSelf.groupId, completion: { [weak self] in
|
||||
self?.chatListDisplayNode.chatListNode.clearHighlightAnimated(true)
|
||||
})
|
||||
}
|
||||
@ -726,9 +730,16 @@ public class ChatListController: TelegramController, UIViewControllerPreviewingD
|
||||
|> deliverOnMainQueue).start(next: { [weak strongSelf] actualPeerId in
|
||||
if let strongSelf = strongSelf {
|
||||
if let navigationController = strongSelf.navigationController as? NavigationController {
|
||||
|
||||
var scrollToEndIfExists = false
|
||||
if let layout = strongSelf.validLayout, case .regular = layout.metrics.widthClass {
|
||||
scrollToEndIfExists = true
|
||||
}
|
||||
|
||||
|
||||
navigateToChatController(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(actualPeerId), messageId: messageId, purposefulAction: {
|
||||
self?.deactivateSearch(animated: false)
|
||||
})
|
||||
}, scrollToEndIfExists: scrollToEndIfExists, options: strongSelf.groupId == PeerGroupId.root ? [.removeOnMasterDetails] : [])
|
||||
strongSelf.chatListDisplayNode.chatListNode.clearHighlightAnimated(true)
|
||||
}
|
||||
}
|
||||
@ -748,12 +759,18 @@ public class ChatListController: TelegramController, UIViewControllerPreviewingD
|
||||
strongSelf.openMessageFromSearchDisposable.set((storedPeer |> deliverOnMainQueue).start(completed: { [weak strongSelf] in
|
||||
if let strongSelf = strongSelf {
|
||||
if dismissSearch {
|
||||
strongSelf.dismissSearchOnDisappear = true
|
||||
strongSelf.deactivateSearch(animated: true)
|
||||
}
|
||||
|
||||
var scrollToEndIfExists = false
|
||||
if let layout = strongSelf.validLayout, case .regular = layout.metrics.widthClass {
|
||||
scrollToEndIfExists = true
|
||||
}
|
||||
|
||||
if let navigationController = strongSelf.navigationController as? NavigationController {
|
||||
navigateToChatController(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id), purposefulAction: { [weak self] in
|
||||
self?.deactivateSearch(animated: false)
|
||||
})
|
||||
}, scrollToEndIfExists: scrollToEndIfExists, options: strongSelf.groupId == PeerGroupId.root ? [.removeOnMasterDetails] : [])
|
||||
strongSelf.chatListDisplayNode.chatListNode.clearHighlightAnimated(true)
|
||||
}
|
||||
}
|
||||
@ -1095,10 +1112,6 @@ public class ChatListController: TelegramController, UIViewControllerPreviewingD
|
||||
|
||||
override public func navigationStackConfigurationUpdated(next: [ViewController]) {
|
||||
super.navigationStackConfigurationUpdated(next: next)
|
||||
|
||||
let chatLocation = (next.first as? ChatController)?.chatLocation
|
||||
|
||||
self.chatListDisplayNode.chatListNode.updateSelectedChatLocation(chatLocation, progress: 1.0, transition: .immediate)
|
||||
}
|
||||
|
||||
@objc func editPressed() {
|
||||
@ -1110,6 +1123,7 @@ public class ChatListController: TelegramController, UIViewControllerPreviewingD
|
||||
self.navigationItem.rightBarButtonItem = editItem
|
||||
}
|
||||
self.searchContentNode?.setIsEnabled(false, animated: true)
|
||||
(self.navigationController as? NavigationController)?.updateMasterDetailsBlackout(.details, transition: .animated(duration: 0.5, curve: .spring))
|
||||
self.chatListDisplayNode.chatListNode.updateState { state in
|
||||
var state = state
|
||||
state.editing = true
|
||||
@ -1126,6 +1140,7 @@ public class ChatListController: TelegramController, UIViewControllerPreviewingD
|
||||
} else {
|
||||
self.navigationItem.rightBarButtonItem = editItem
|
||||
}
|
||||
(self.navigationController as? NavigationController)?.updateMasterDetailsBlackout(nil, transition: .animated(duration: 0.4, curve: .spring))
|
||||
self.searchContentNode?.setIsEnabled(true, animated: true)
|
||||
self.chatListDisplayNode.chatListNode.updateState { state in
|
||||
var state = state
|
||||
|
||||
@ -504,7 +504,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
self.updateIsHighlighted(transition: (animated && !highlighted) ? .animated(duration: 0.3, curve: .easeInOut) : .immediate)
|
||||
}
|
||||
|
||||
func updateIsHighlighted(transition: ContainedViewLayoutTransition) {
|
||||
var reallyHighlighted: Bool {
|
||||
var reallyHighlighted = self.isHighlighted
|
||||
if let item = self.item {
|
||||
if let itemChatLocation = item.content.chatLocation {
|
||||
@ -513,6 +513,11 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
}
|
||||
}
|
||||
}
|
||||
return reallyHighlighted
|
||||
}
|
||||
|
||||
func updateIsHighlighted(transition: ContainedViewLayoutTransition) {
|
||||
|
||||
|
||||
if reallyHighlighted {
|
||||
if self.highlightedBackgroundNode.supernode == nil {
|
||||
@ -1193,7 +1198,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
transition.updateFrame(node: strongSelf.onlineNode, frame: onlineFrame)
|
||||
|
||||
let onlineIcon: UIImage?
|
||||
if strongSelf.isHighlighted {
|
||||
if strongSelf.reallyHighlighted {
|
||||
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .highlighted)
|
||||
} else if item.index.pinningIndex != nil {
|
||||
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .pinned)
|
||||
|
||||
@ -57,6 +57,6 @@ extension PeekControllerTheme {
|
||||
|
||||
public extension NavigationControllerTheme {
|
||||
convenience init(presentationTheme: PresentationTheme) {
|
||||
self.init(navigationBar: NavigationBarTheme(rootControllerTheme: presentationTheme), emptyAreaColor: presentationTheme.chatList.backgroundColor, emptyDetailIcon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/EmptyMasterDetailIcon"), color: presentationTheme.chatList.messageTextColor.withAlphaComponent(0.2)))
|
||||
self.init(navigationBar: NavigationBarTheme(rootControllerTheme: presentationTheme), emptyAreaColor: presentationTheme.chatList.backgroundColor)
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,12 +94,21 @@ private enum ContactListNodeEntryId: Hashable {
|
||||
}
|
||||
}
|
||||
|
||||
final class ContactItemHighlighting {
|
||||
var chatLocation: ChatLocation?
|
||||
init(chatLocation: ChatLocation? = nil) {
|
||||
self.chatLocation = chatLocation
|
||||
}
|
||||
}
|
||||
|
||||
private final class ContactListNodeInteraction {
|
||||
let activateSearch: () -> Void
|
||||
let openSortMenu: () -> Void
|
||||
let authorize: () -> Void
|
||||
let suppressWarning: () -> Void
|
||||
let openPeer: (ContactListPeer) -> Void
|
||||
fileprivate let activateSearch: () -> Void
|
||||
fileprivate let openSortMenu: () -> Void
|
||||
fileprivate let authorize: () -> Void
|
||||
fileprivate let suppressWarning: () -> Void
|
||||
fileprivate let openPeer: (ContactListPeer) -> Void
|
||||
|
||||
let itemHighlighting = ContactItemHighlighting()
|
||||
|
||||
init(activateSearch: @escaping () -> Void, openSortMenu: @escaping () -> Void, authorize: @escaping () -> Void, suppressWarning: @escaping () -> Void, openPeer: @escaping (ContactListPeer) -> Void) {
|
||||
self.activateSearch = activateSearch
|
||||
@ -191,6 +200,8 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
func item(account: Account, interaction: ContactListNodeInteraction) -> ListViewItem {
|
||||
switch self {
|
||||
case let .search(theme, strings):
|
||||
@ -245,7 +256,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
}
|
||||
return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .peer, peer: itemPeer, status: status, enabled: enabled, selection: selection, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in
|
||||
interaction.openPeer(peer)
|
||||
})
|
||||
}, itemHighlighting: interaction.itemHighlighting)
|
||||
}
|
||||
}
|
||||
|
||||
@ -775,6 +786,7 @@ final class ContactListNode: ASDisplayNode {
|
||||
var selectionState: ContactListNodeGroupSelectionState? {
|
||||
return self.selectionStateValue
|
||||
}
|
||||
private var interaction: ContactListNodeInteraction?
|
||||
|
||||
private var enableUpdatesValue = false
|
||||
var enableUpdates: Bool {
|
||||
@ -929,6 +941,8 @@ final class ContactListNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
self.interaction = interaction
|
||||
|
||||
let context = self.context
|
||||
var firstTime: Int32 = 1
|
||||
let selectionStateSignal = self.selectionStatePromise.get()
|
||||
@ -1318,6 +1332,17 @@ final class ContactListNode: ASDisplayNode {
|
||||
self.enableUpdates = true
|
||||
}
|
||||
|
||||
func updateSelectedChatLocation(_ chatLocation: ChatLocation?, progress: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
|
||||
self.interaction?.itemHighlighting.chatLocation = chatLocation
|
||||
|
||||
self.listNode.forEachItemNode { itemNode in
|
||||
if let itemNode = itemNode as? ContactsPeerItemNode {
|
||||
itemNode.updateIsHighlighted(transition: transition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
self.presentationDataDisposable?.dispose()
|
||||
|
||||
@ -56,6 +56,7 @@ public class ContactsController: ViewController {
|
||||
private var contactsNode: ContactsControllerNode {
|
||||
return self.displayNode as! ContactsControllerNode
|
||||
}
|
||||
private var validLayout: ContainerViewLayout?
|
||||
|
||||
private let index: PeerNameIndex = .lastNameFirst
|
||||
|
||||
@ -73,6 +74,12 @@ public class ContactsController: ViewController {
|
||||
|
||||
var switchToChatsController: (() -> Void)?
|
||||
|
||||
public override var navigationCustomData: Any? {
|
||||
didSet {
|
||||
self.contactsNode.contactListNode.updateSelectedChatLocation(self.navigationCustomData as? ChatLocation, progress: 1, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
public init(context: AccountContext) {
|
||||
self.context = context
|
||||
|
||||
@ -195,12 +202,19 @@ public class ContactsController: ViewController {
|
||||
switch peer {
|
||||
case let .peer(peer, _, _):
|
||||
if let navigationController = strongSelf.navigationController as? NavigationController {
|
||||
|
||||
var scrollToEndIfExists = false
|
||||
if let layout = strongSelf.validLayout, case .regular = layout.metrics.widthClass {
|
||||
scrollToEndIfExists = true
|
||||
}
|
||||
|
||||
|
||||
navigateToChatController(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id), purposefulAction: { [weak self] in
|
||||
if fromSearch {
|
||||
self?.deactivateSearch(animated: false)
|
||||
self?.switchToChatsController?()
|
||||
}
|
||||
}, completion: { [weak self] in
|
||||
}, scrollToEndIfExists: scrollToEndIfExists, options: [.removeOnMasterDetails], completion: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.contactsNode.contactListNode.listNode.clearHighlightAnimated(true)
|
||||
}
|
||||
|
||||
@ -125,6 +125,7 @@ class ContactsPeerItem: ListViewItem {
|
||||
let action: (ContactsPeerItemPeer) -> Void
|
||||
let setPeerIdWithRevealedOptions: ((PeerId?, PeerId?) -> Void)?
|
||||
let deletePeer: ((PeerId) -> Void)?
|
||||
let itemHighlighting: ContactItemHighlighting?
|
||||
|
||||
let selectable: Bool
|
||||
|
||||
@ -132,7 +133,7 @@ class ContactsPeerItem: ListViewItem {
|
||||
|
||||
let header: ListViewItemHeader?
|
||||
|
||||
init(theme: PresentationTheme, strings: PresentationStrings, sortOrder: PresentationPersonNameOrder, displayOrder: PresentationPersonNameOrder, account: Account, peerMode: ContactsPeerItemPeerMode, peer: ContactsPeerItemPeer, status: ContactsPeerItemStatus, badge: ContactsPeerItemBadge? = nil, enabled: Bool, selection: ContactsPeerItemSelection, editing: ContactsPeerItemEditing, options: [ItemListPeerItemRevealOption] = [], actionIcon: ContactsPeerItemActionIcon = .none, index: PeerNameIndex?, header: ListViewItemHeader?, action: @escaping (ContactsPeerItemPeer) -> Void, setPeerIdWithRevealedOptions: ((PeerId?, PeerId?) -> Void)? = nil, deletePeer: ((PeerId) -> Void)? = nil) {
|
||||
init(theme: PresentationTheme, strings: PresentationStrings, sortOrder: PresentationPersonNameOrder, displayOrder: PresentationPersonNameOrder, account: Account, peerMode: ContactsPeerItemPeerMode, peer: ContactsPeerItemPeer, status: ContactsPeerItemStatus, badge: ContactsPeerItemBadge? = nil, enabled: Bool, selection: ContactsPeerItemSelection, editing: ContactsPeerItemEditing, options: [ItemListPeerItemRevealOption] = [], actionIcon: ContactsPeerItemActionIcon = .none, index: PeerNameIndex?, header: ListViewItemHeader?, action: @escaping (ContactsPeerItemPeer) -> Void, setPeerIdWithRevealedOptions: ((PeerId?, PeerId?) -> Void)? = nil, deletePeer: ((PeerId) -> Void)? = nil, itemHighlighting: ContactItemHighlighting? = nil) {
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
self.sortOrder = sortOrder
|
||||
@ -151,7 +152,7 @@ class ContactsPeerItem: ListViewItem {
|
||||
self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions
|
||||
self.deletePeer = deletePeer
|
||||
self.header = header
|
||||
|
||||
self.itemHighlighting = itemHighlighting
|
||||
self.selectable = self.enabled
|
||||
|
||||
if let index = index {
|
||||
@ -298,6 +299,9 @@ class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
private var avatarState: (Account, Peer?)?
|
||||
|
||||
private var isHighlighted: Bool = false
|
||||
|
||||
|
||||
private var peerPresenceManager: PeerPresenceStatusManager?
|
||||
private var layoutParams: (ContactsPeerItem, ListViewItemLayoutParams, Bool, Bool, Bool)?
|
||||
var chatPeer: Peer? {
|
||||
@ -365,25 +369,65 @@ class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
override func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
|
||||
super.setHighlighted(highlighted, at: point, animated: animated)
|
||||
|
||||
if highlighted && self.selectionNode == nil {
|
||||
self.highlightedBackgroundNode.alpha = 1.0
|
||||
self.isHighlighted = highlighted
|
||||
|
||||
self.updateIsHighlighted(transition: (animated && !highlighted) ? .animated(duration: 0.3, curve: .easeInOut) : .immediate)
|
||||
|
||||
// if highlighted && self.selectionNode == nil {
|
||||
// self.highlightedBackgroundNode.alpha = 1.0
|
||||
// if self.highlightedBackgroundNode.supernode == nil {
|
||||
// self.insertSubnode(self.highlightedBackgroundNode, aboveSubnode: self.separatorNode)
|
||||
// }
|
||||
// } 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()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
func updateIsHighlighted(transition: ContainedViewLayoutTransition) {
|
||||
var reallyHighlighted = self.isHighlighted
|
||||
if let item = self.item {
|
||||
switch item.peer {
|
||||
case let .peer(_, chatPeer):
|
||||
if let peer = chatPeer {
|
||||
if ChatLocation.peer(peer.id) == item.itemHighlighting?.chatLocation {
|
||||
reallyHighlighted = true
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if reallyHighlighted {
|
||||
if self.highlightedBackgroundNode.supernode == nil {
|
||||
self.insertSubnode(self.highlightedBackgroundNode, aboveSubnode: self.separatorNode)
|
||||
self.highlightedBackgroundNode.alpha = 0.0
|
||||
}
|
||||
self.highlightedBackgroundNode.layer.removeAllAnimations()
|
||||
transition.updateAlpha(layer: self.highlightedBackgroundNode.layer, alpha: 1.0)
|
||||
} 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
|
||||
transition.updateAlpha(layer: self.highlightedBackgroundNode.layer, alpha: 0.0, completion: { [weak self] completed in
|
||||
if let strongSelf = self {
|
||||
if completed {
|
||||
strongSelf.highlightedBackgroundNode.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
})
|
||||
self.highlightedBackgroundNode.alpha = 0.0
|
||||
} else {
|
||||
self.highlightedBackgroundNode.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ public enum NavigateToChatKeepStack {
|
||||
case never
|
||||
}
|
||||
|
||||
public func navigateToChatController(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: ChatLocation, messageId: MessageId? = nil, botStart: ChatControllerInitialBotStart? = nil, keepStack: NavigateToChatKeepStack = .default, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, animated: Bool = true, parentGroupId: PeerGroupId? = nil, completion: @escaping () -> Void = {}) {
|
||||
public func navigateToChatController(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: ChatLocation, messageId: MessageId? = nil, botStart: ChatControllerInitialBotStart? = nil, keepStack: NavigateToChatKeepStack = .default, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, completion: @escaping () -> Void = {}) {
|
||||
var found = false
|
||||
var isFirst = true
|
||||
for controller in navigationController.viewControllers.reversed() {
|
||||
@ -72,9 +72,9 @@ public func navigateToChatController(navigationController: NavigationController,
|
||||
}
|
||||
})
|
||||
if viewControllers.isEmpty {
|
||||
navigationController.replaceAllButRootController(controller, animated: animated, completion: completion)
|
||||
navigationController.replaceAllButRootController(controller, animated: animated, animationOptions: options, completion: completion)
|
||||
} else {
|
||||
navigationController.replaceControllersAndPush(controllers: viewControllers, controller: controller, animated: animated, completion: completion)
|
||||
navigationController.replaceControllersAndPush(controllers: viewControllers, controller: controller, animated: animated, options: options, completion: completion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1243,7 +1243,7 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|
||||
|
||||
let controller = SettingsControllerImpl(currentContext: context, contextValue: contextValue, state: signal, tabBarItem: tabBarItem, accountsAndPeers: accountsAndPeers.get())
|
||||
pushControllerImpl = { [weak controller] value in
|
||||
(controller?.navigationController as? NavigationController)?.replaceAllButRootController(value, animated: true)
|
||||
(controller?.navigationController as? NavigationController)?.replaceAllButRootController(value, animated: true, animationOptions: [.removeOnMasterDetails])
|
||||
}
|
||||
presentControllerImpl = { [weak controller] value, arguments in
|
||||
controller?.present(value, in: .window(.root), with: arguments ?? ViewControllerPresentationArguments(presentationAnimation: .modalSheet), blockInteraction: true)
|
||||
|
||||
@ -26,16 +26,44 @@ public final class TelegramRootController: NavigationController {
|
||||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
super.init(mode: .automaticMasterDetail, theme: NavigationControllerTheme(presentationTheme: self.presentationData.theme))
|
||||
let navigationDetailsBackgroundMode: NavigationEmptyDetailsBackgoundMode?
|
||||
switch presentationData.chatWallpaper {
|
||||
case .color:
|
||||
let image = generateTintedImage(image: UIImage(bundleImageName: "Chat List/EmptyMasterDetailIcon"), color: presentationData.theme.chatList.messageTextColor.withAlphaComponent(0.2))
|
||||
navigationDetailsBackgroundMode = image != nil ? .image(image!) : nil
|
||||
default:
|
||||
let image = chatControllerBackgroundImage(wallpaper: presentationData.chatWallpaper, mediaBox: context.account.postbox.mediaBox)
|
||||
navigationDetailsBackgroundMode = image != nil ? .wallpaper(image!) : nil
|
||||
}
|
||||
|
||||
super.init(mode: .automaticMasterDetail, theme: NavigationControllerTheme(presentationTheme: self.presentationData.theme), backgroundDetailsMode: navigationDetailsBackgroundMode)
|
||||
|
||||
self.presentationDataDisposable = (context.sharedContext.presentationData
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
||||
if let strongSelf = self {
|
||||
|
||||
if presentationData.chatWallpaper != strongSelf.presentationData.chatWallpaper {
|
||||
let navigationDetailsBackgroundMode: NavigationEmptyDetailsBackgoundMode?
|
||||
switch presentationData.chatWallpaper {
|
||||
case .color:
|
||||
let image = generateTintedImage(image: UIImage(bundleImageName: "Chat List/EmptyMasterDetailIcon"), color: presentationData.theme.chatList.messageTextColor.withAlphaComponent(0.2))
|
||||
navigationDetailsBackgroundMode = image != nil ? .image(image!) : nil
|
||||
default:
|
||||
let image = chatControllerBackgroundImage(wallpaper: presentationData.chatWallpaper, mediaBox: strongSelf.context.account.postbox.mediaBox)
|
||||
navigationDetailsBackgroundMode = image != nil ? .wallpaper(image!) : nil
|
||||
}
|
||||
strongSelf.updateBackgroundDetailsMode(navigationDetailsBackgroundMode, transition: .immediate)
|
||||
}
|
||||
|
||||
|
||||
|
||||
let previousTheme = strongSelf.presentationData.theme
|
||||
strongSelf.presentationData = presentationData
|
||||
if previousTheme !== presentationData.theme {
|
||||
strongSelf.rootTabController?.updateTheme(navigationBarPresentationData: NavigationBarPresentationData(presentationData: presentationData), theme: TabBarControllerTheme(rootControllerTheme: presentationData.theme))
|
||||
strongSelf.rootTabController?.statusBar.statusBarStyle = presentationData.theme.rootController.statusBar.style.style
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user