no message

This commit is contained in:
Peter 2018-04-11 23:41:52 +04:00
parent 95614c8121
commit a85bfb2033
10 changed files with 235 additions and 194 deletions

View File

@ -112,6 +112,7 @@
D05CC3271B69725400E235A3 /* NavigationBackArrowLight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D05CC3261B69725400E235A3 /* NavigationBackArrowLight@2x.png */; }; D05CC3271B69725400E235A3 /* NavigationBackArrowLight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D05CC3261B69725400E235A3 /* NavigationBackArrowLight@2x.png */; };
D05CC3291B69750D00E235A3 /* InteractiveTransitionGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05CC3281B69750D00E235A3 /* InteractiveTransitionGestureRecognizer.swift */; }; D05CC3291B69750D00E235A3 /* InteractiveTransitionGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05CC3281B69750D00E235A3 /* InteractiveTransitionGestureRecognizer.swift */; };
D06B76DB20592A97006E9EEA /* LayoutSizes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06B76DA20592A97006E9EEA /* LayoutSizes.swift */; }; D06B76DB20592A97006E9EEA /* LayoutSizes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06B76DA20592A97006E9EEA /* LayoutSizes.swift */; };
D06D37A220779C82009219B6 /* VolumeControlStatusBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06D37A120779C82009219B6 /* VolumeControlStatusBar.swift */; };
D06EE8451B7140FF00837186 /* Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06EE8441B7140FF00837186 /* Font.swift */; }; D06EE8451B7140FF00837186 /* Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06EE8441B7140FF00837186 /* Font.swift */; };
D077B8E91F4637040046D27A /* NavigationBarBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D077B8E81F4637040046D27A /* NavigationBarBadge.swift */; }; D077B8E91F4637040046D27A /* NavigationBarBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D077B8E81F4637040046D27A /* NavigationBarBadge.swift */; };
D081229D1D19AA1C005F7395 /* ContainerViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = D081229C1D19AA1C005F7395 /* ContainerViewLayout.swift */; }; D081229D1D19AA1C005F7395 /* ContainerViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = D081229C1D19AA1C005F7395 /* ContainerViewLayout.swift */; };
@ -286,6 +287,7 @@
D05CC3261B69725400E235A3 /* NavigationBackArrowLight@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NavigationBackArrowLight@2x.png"; sourceTree = "<group>"; }; D05CC3261B69725400E235A3 /* NavigationBackArrowLight@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NavigationBackArrowLight@2x.png"; sourceTree = "<group>"; };
D05CC3281B69750D00E235A3 /* InteractiveTransitionGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InteractiveTransitionGestureRecognizer.swift; sourceTree = "<group>"; }; D05CC3281B69750D00E235A3 /* InteractiveTransitionGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InteractiveTransitionGestureRecognizer.swift; sourceTree = "<group>"; };
D06B76DA20592A97006E9EEA /* LayoutSizes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutSizes.swift; sourceTree = "<group>"; }; D06B76DA20592A97006E9EEA /* LayoutSizes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutSizes.swift; sourceTree = "<group>"; };
D06D37A120779C82009219B6 /* VolumeControlStatusBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VolumeControlStatusBar.swift; sourceTree = "<group>"; };
D06EE8441B7140FF00837186 /* Font.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Font.swift; sourceTree = "<group>"; }; D06EE8441B7140FF00837186 /* Font.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Font.swift; sourceTree = "<group>"; };
D077B8E81F4637040046D27A /* NavigationBarBadge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationBarBadge.swift; sourceTree = "<group>"; }; D077B8E81F4637040046D27A /* NavigationBarBadge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationBarBadge.swift; sourceTree = "<group>"; };
D081229C1D19AA1C005F7395 /* ContainerViewLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContainerViewLayout.swift; sourceTree = "<group>"; }; D081229C1D19AA1C005F7395 /* ContainerViewLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContainerViewLayout.swift; sourceTree = "<group>"; };
@ -669,6 +671,7 @@
D0B3671F1C94A53A00346D2E /* StatusBarProxyNode.swift */, D0B3671F1C94A53A00346D2E /* StatusBarProxyNode.swift */,
D03E7DFE1C96F7B400C07816 /* StatusBarManager.swift */, D03E7DFE1C96F7B400C07816 /* StatusBarManager.swift */,
D03B0E6F1D6331FB00955575 /* StatusBarHost.swift */, D03B0E6F1D6331FB00955575 /* StatusBarHost.swift */,
D06D37A120779C82009219B6 /* VolumeControlStatusBar.swift */,
); );
name = "Status Bar"; name = "Status Bar";
sourceTree = "<group>"; sourceTree = "<group>";
@ -984,6 +987,7 @@
D02958001D6F096000360E5E /* ContextMenuContainerNode.swift in Sources */, D02958001D6F096000360E5E /* ContextMenuContainerNode.swift in Sources */,
D05BE4AB1D1F25E3002BD72C /* PresentationContext.swift in Sources */, D05BE4AB1D1F25E3002BD72C /* PresentationContext.swift in Sources */,
D0C2DFCA1CC4431D0044FF83 /* ListViewItem.swift in Sources */, D0C2DFCA1CC4431D0044FF83 /* ListViewItem.swift in Sources */,
D06D37A220779C82009219B6 /* VolumeControlStatusBar.swift in Sources */,
D05CC2A01B69326400E235A3 /* NavigationController.swift in Sources */, D05CC2A01B69326400E235A3 /* NavigationController.swift in Sources */,
D06EE8451B7140FF00837186 /* Font.swift in Sources */, D06EE8451B7140FF00837186 /* Font.swift in Sources */,
D0CA3F8A2073F7650042D2B6 /* LinkHighlightingNode.swift in Sources */, D0CA3F8A2073F7650042D2B6 /* LinkHighlightingNode.swift in Sources */,

View File

@ -32,10 +32,6 @@ public struct LayoutMetrics: Equatable {
self.widthClass = .compact self.widthClass = .compact
self.heightClass = .compact self.heightClass = .compact
} }
public static func ==(lhs: LayoutMetrics, rhs: LayoutMetrics) -> Bool {
return lhs.widthClass == rhs.widthClass && lhs.heightClass == rhs.heightClass
}
} }
public struct ContainerViewLayout: Equatable { public struct ContainerViewLayout: Equatable {
@ -81,56 +77,4 @@ public struct ContainerViewLayout: Equatable {
public func withUpdatedMetrics(_ metrics: LayoutMetrics) -> ContainerViewLayout { public func withUpdatedMetrics(_ metrics: LayoutMetrics) -> ContainerViewLayout {
return ContainerViewLayout(size: self.size, metrics: metrics, intrinsicInsets: self.intrinsicInsets, safeInsets: self.safeInsets, statusBarHeight: self.statusBarHeight, inputHeight: self.inputHeight, standardInputHeight: self.standardInputHeight, inputHeightIsInteractivellyChanging: self.inputHeightIsInteractivellyChanging) return ContainerViewLayout(size: self.size, metrics: metrics, intrinsicInsets: self.intrinsicInsets, safeInsets: self.safeInsets, statusBarHeight: self.statusBarHeight, inputHeight: self.inputHeight, standardInputHeight: self.standardInputHeight, inputHeightIsInteractivellyChanging: self.inputHeightIsInteractivellyChanging)
} }
public static func ==(lhs: ContainerViewLayout, rhs: ContainerViewLayout) -> Bool {
if !lhs.size.equalTo(rhs.size) {
return false
}
if lhs.metrics != rhs.metrics {
return false
}
if lhs.intrinsicInsets != rhs.intrinsicInsets {
return false
}
if lhs.safeInsets != rhs.safeInsets {
return false
}
if let lhsStatusBarHeight = lhs.statusBarHeight {
if let rhsStatusBarHeight = rhs.statusBarHeight {
if !lhsStatusBarHeight.isEqual(to: rhsStatusBarHeight) {
return false
}
} else {
return false
}
} else if let _ = rhs.statusBarHeight {
return false
}
if let lhsInputHeight = lhs.inputHeight {
if let rhsInputHeight = rhs.inputHeight {
if !lhsInputHeight.isEqual(to: rhsInputHeight) {
return false
}
} else {
return false
}
} else if let _ = rhs.inputHeight {
return false
}
if !lhs.standardInputHeight.isEqual(to: rhs.standardInputHeight) {
return false
}
if lhs.inputHeightIsInteractivellyChanging != rhs.inputHeightIsInteractivellyChanging {
return false
}
return true
}
} }

View File

@ -7,10 +7,6 @@ private struct CachedMaskParams: Equatable {
let arrowOnBottom: Bool let arrowOnBottom: Bool
} }
private func ==(lhs: CachedMaskParams, rhs: CachedMaskParams) -> Bool {
return lhs.size.equalTo(rhs.size) && lhs.relativeArrowPosition.isEqual(to: rhs.relativeArrowPosition) && lhs.arrowOnBottom == rhs.arrowOnBottom
}
private final class ContextMenuContainerMaskView: UIView { private final class ContextMenuContainerMaskView: UIView {
override class var layerClass: AnyClass { override class var layerClass: AnyClass {
return CAShapeLayer.self return CAShapeLayer.self

View File

@ -53,23 +53,6 @@ public struct GridNodeScrollToItem {
public enum GridNodeLayoutType: Equatable { public enum GridNodeLayoutType: Equatable {
case fixed(itemSize: CGSize, lineSpacing: CGFloat) case fixed(itemSize: CGSize, lineSpacing: CGFloat)
case balanced(idealHeight: CGFloat) case balanced(idealHeight: CGFloat)
public static func ==(lhs: GridNodeLayoutType, rhs: GridNodeLayoutType) -> Bool {
switch lhs {
case let .fixed(itemSize, lineSpacing):
if case .fixed(itemSize, lineSpacing) = rhs {
return true
} else {
return false
}
case let .balanced(idealHeight):
if case .balanced(idealHeight) = rhs {
return true
} else {
return false
}
}
}
} }
public struct GridNodeLayout: Equatable { public struct GridNodeLayout: Equatable {
@ -86,10 +69,6 @@ public struct GridNodeLayout: Equatable {
self.preloadSize = preloadSize self.preloadSize = preloadSize
self.type = type self.type = type
} }
public static func ==(lhs: GridNodeLayout, rhs: GridNodeLayout) -> Bool {
return lhs.size.equalTo(rhs.size) && lhs.insets == rhs.insets && lhs.preloadSize.isEqual(to: rhs.preloadSize) && lhs.type == rhs.type
}
} }
public struct GridNodeUpdateLayout { public struct GridNodeUpdateLayout {
@ -180,13 +159,9 @@ private final class GridNodeItemLayout {
public struct GridNodeDisplayedItemRange: Equatable { public struct GridNodeDisplayedItemRange: Equatable {
public let loadedRange: Range<Int>? public let loadedRange: Range<Int>?
public let visibleRange: Range<Int>? public let visibleRange: Range<Int>?
public static func ==(lhs: GridNodeDisplayedItemRange, rhs: GridNodeDisplayedItemRange) -> Bool {
return lhs.loadedRange == rhs.loadedRange && lhs.visibleRange == rhs.visibleRange
}
} }
private struct WrappedGridSection: Hashable { private struct WrappedGridSection: Equatable, Hashable {
let section: GridSection let section: GridSection
init(_ section: GridSection) { init(_ section: GridSection) {

View File

@ -14,29 +14,6 @@ public enum ListViewScrollPosition: Equatable {
case top(CGFloat) case top(CGFloat)
case bottom(CGFloat) case bottom(CGFloat)
case center(ListViewCenterScrollPositionOverflow) case center(ListViewCenterScrollPositionOverflow)
public static func ==(lhs: ListViewScrollPosition, rhs: ListViewScrollPosition) -> Bool {
switch lhs {
case let .top(offset):
if case .top(offset) = rhs {
return true
} else {
return false
}
case let .bottom(offset):
if case .bottom(offset) = rhs {
return true
} else {
return false
}
case let .center(overflow):
if case .center(overflow) = rhs {
return true
} else {
return false
}
}
}
} }
public enum ListViewScrollToItemDirectionHint { public enum ListViewScrollToItemDirectionHint {
@ -147,20 +124,12 @@ public struct ListViewUpdateSizeAndInsets {
public struct ListViewItemRange: Equatable { public struct ListViewItemRange: Equatable {
public let firstIndex: Int public let firstIndex: Int
public let lastIndex: Int public let lastIndex: Int
public static func ==(lhs: ListViewItemRange, rhs: ListViewItemRange) -> Bool {
return lhs.firstIndex == rhs.firstIndex && lhs.lastIndex == rhs.lastIndex
}
} }
public struct ListViewVisibleItemRange: Equatable { public struct ListViewVisibleItemRange: Equatable {
public let firstIndex: Int public let firstIndex: Int
public let firstIndexFullyVisible: Bool public let firstIndexFullyVisible: Bool
public let lastIndex: Int public let lastIndex: Int
public static func ==(lhs: ListViewVisibleItemRange, rhs: ListViewVisibleItemRange) -> Bool {
return lhs.firstIndex == rhs.firstIndex && lhs.firstIndexFullyVisible == rhs.firstIndexFullyVisible && lhs.lastIndex == rhs.lastIndex
}
} }
public struct ListViewDisplayedItemRange: Equatable { public struct ListViewDisplayedItemRange: Equatable {
@ -168,10 +137,6 @@ public struct ListViewDisplayedItemRange: Equatable {
public let visibleRange: ListViewVisibleItemRange? public let visibleRange: ListViewVisibleItemRange?
} }
public func ==(lhs: ListViewDisplayedItemRange, rhs: ListViewDisplayedItemRange) -> Bool {
return lhs.loadedRange == rhs.loadedRange && lhs.visibleRange == rhs.visibleRange
}
struct IndexRange { struct IndexRange {
let first: Int let first: Int
let last: Int let last: Int

View File

@ -1,5 +1,6 @@
import Foundation import Foundation
import AsyncDisplayKit import AsyncDisplayKit
import SwiftSignalKit
private struct MappedStatusBar { private struct MappedStatusBar {
let style: StatusBarStyle let style: StatusBarStyle
@ -70,27 +71,79 @@ private func displayHiddenAnimation() -> CAAnimation {
class StatusBarManager { class StatusBarManager {
private var host: StatusBarHost private var host: StatusBarHost
private let volumeControlStatusBar: VolumeControlStatusBar
private let volumeControlStatusBarNode: VolumeControlStatusBarNode
private var surfaces: [StatusBarSurface] = [] private var surfaces: [StatusBarSurface] = []
private var validParams: (withSafeInsets: Bool, forceInCallStatusBarText: String?, forceHiddenBySystemWindows: Bool)?
var inCallNavigate: (() -> Void)? var inCallNavigate: (() -> Void)?
init(host: StatusBarHost) { private var volumeTimer: SwiftSignalKit.Timer?
init(host: StatusBarHost, volumeControlStatusBar: VolumeControlStatusBar, volumeControlStatusBarNode: VolumeControlStatusBarNode) {
self.host = host self.host = host
self.volumeControlStatusBar = volumeControlStatusBar
self.volumeControlStatusBarNode = volumeControlStatusBarNode
self.volumeControlStatusBarNode.isHidden = true
self.volumeControlStatusBar.valueChanged = { [weak self] previous, updated in
if let strongSelf = self {
strongSelf.startVolumeTimer()
strongSelf.volumeControlStatusBarNode.updateValue(from: CGFloat(previous), to: CGFloat(updated))
}
}
}
private func startVolumeTimer() {
self.volumeTimer?.invalidate()
let timer = SwiftSignalKit.Timer(timeout: 2.0, repeat: false, completion: { [weak self] in
self?.endVolumeTimer()
}, queue: Queue.mainQueue())
self.volumeTimer = timer
timer.start()
if self.volumeControlStatusBarNode.isHidden {
self.volumeControlStatusBarNode.isHidden = false
self.volumeControlStatusBarNode.alpha = 1.0
self.volumeControlStatusBarNode.allowsGroupOpacity = true
self.volumeControlStatusBarNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, delay: 0.18, completion: { [weak self] _ in
self?.volumeControlStatusBarNode.allowsGroupOpacity = false
})
}
if let (withSafeInsets, forceInCallStatusBarText, forceHiddenBySystemWindows) = self.validParams {
self.updateSurfaces(self.surfaces, withSafeInsets: withSafeInsets, forceInCallStatusBarText: forceInCallStatusBarText, forceHiddenBySystemWindows: forceHiddenBySystemWindows, animated: false, alphaTransition: .animated(duration: 0.2, curve: .easeInOut))
}
}
private func endVolumeTimer() {
self.volumeControlStatusBarNode.alpha = 0.0
self.volumeControlStatusBarNode.allowsGroupOpacity = true
self.volumeControlStatusBarNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, completion: { [weak self] completed in
if let strongSelf = self, completed {
strongSelf.volumeControlStatusBarNode.isHidden = true
strongSelf.volumeControlStatusBarNode.allowsGroupOpacity = false
}
})
self.volumeTimer = nil
if let (withSafeInsets, forceInCallStatusBarText, forceHiddenBySystemWindows) = self.validParams {
self.updateSurfaces(self.surfaces, withSafeInsets: withSafeInsets, forceInCallStatusBarText: forceInCallStatusBarText, forceHiddenBySystemWindows: forceHiddenBySystemWindows, animated: false, alphaTransition: .animated(duration: 0.2, curve: .easeInOut))
}
} }
func updateState(surfaces: [StatusBarSurface], withSafeInsets: Bool, forceInCallStatusBarText: String?, forceHiddenBySystemWindows: Bool, animated: Bool) { func updateState(surfaces: [StatusBarSurface], withSafeInsets: Bool, forceInCallStatusBarText: String?, forceHiddenBySystemWindows: Bool, animated: Bool) {
let previousSurfaces = self.surfaces let previousSurfaces = self.surfaces
self.surfaces = surfaces self.surfaces = surfaces
self.updateSurfaces(previousSurfaces, withSafeInsets: withSafeInsets, forceInCallStatusBarText: forceInCallStatusBarText, forceHiddenBySystemWindows: forceHiddenBySystemWindows, animated: animated) self.updateSurfaces(previousSurfaces, withSafeInsets: withSafeInsets, forceInCallStatusBarText: forceInCallStatusBarText, forceHiddenBySystemWindows: forceHiddenBySystemWindows, animated: animated, alphaTransition: .immediate)
} }
private func updateSurfaces(_ previousSurfaces: [StatusBarSurface], withSafeInsets: Bool, forceInCallStatusBarText: String?, forceHiddenBySystemWindows: Bool, animated: Bool) { private func updateSurfaces(_ previousSurfaces: [StatusBarSurface], withSafeInsets: Bool, forceInCallStatusBarText: String?, forceHiddenBySystemWindows: Bool, animated: Bool, alphaTransition: ContainedViewLayoutTransition) {
let statusBarFrame = self.host.statusBarFrame let statusBarFrame = self.host.statusBarFrame
guard let statusBarView = self.host.statusBarView else { guard let statusBarView = self.host.statusBarView else {
return return
} }
self.validParams = (withSafeInsets, forceInCallStatusBarText, forceHiddenBySystemWindows)
if self.host.statusBarWindow?.isUserInteractionEnabled != (forceInCallStatusBarText == nil) { if self.host.statusBarWindow?.isUserInteractionEnabled != (forceInCallStatusBarText == nil) {
self.host.statusBarWindow?.isUserInteractionEnabled = (forceInCallStatusBarText == nil) self.host.statusBarWindow?.isUserInteractionEnabled = (forceInCallStatusBarText == nil)
} }
@ -215,6 +268,11 @@ class StatusBarManager {
statusBar.updateState(statusBar: statusBarView, withSafeInsets: withSafeInsets, inCallText: forceInCallStatusBarText, animated: animated) statusBar.updateState(statusBar: statusBarView, withSafeInsets: withSafeInsets, inCallText: forceInCallStatusBarText, animated: animated)
} }
if self.volumeTimer != nil {
globalStatusBar?.1 = 0.0
}
self.volumeControlStatusBarNode.isDark = globalStatusBar?.0.systemStyle == UIStatusBarStyle.lightContent
if let globalStatusBar = globalStatusBar, !forceHiddenBySystemWindows { if let globalStatusBar = globalStatusBar, !forceHiddenBySystemWindows {
let statusBarStyle: UIStatusBarStyle let statusBarStyle: UIStatusBarStyle
if forceInCallStatusBarText != nil { if forceInCallStatusBarText != nil {
@ -226,7 +284,7 @@ class StatusBarManager {
self.host.statusBarStyle = statusBarStyle self.host.statusBarStyle = statusBarStyle
} }
if let statusBarWindow = self.host.statusBarWindow { if let statusBarWindow = self.host.statusBarWindow {
statusBarView.alpha = globalStatusBar.1 alphaTransition.updateAlpha(layer: statusBarView.layer, alpha: globalStatusBar.1)
var statusBarBounds = statusBarWindow.bounds var statusBarBounds = statusBarWindow.bounds
if !statusBarBounds.origin.y.isEqual(to: globalStatusBar.2) { if !statusBarBounds.origin.y.isEqual(to: globalStatusBar.2) {
statusBarBounds.origin.y = globalStatusBar.2 statusBarBounds.origin.y = globalStatusBar.2

View File

@ -28,10 +28,6 @@ public struct TextNodeCutout: Equatable {
self.position = position self.position = position
self.size = size self.size = size
} }
public static func ==(lhs: TextNodeCutout, rhs: TextNodeCutout) -> Bool {
return lhs.position == rhs.position && lhs.size == rhs.size
}
} }
public final class TextNodeLayoutArguments { public final class TextNodeLayoutArguments {

View File

@ -0,0 +1,136 @@
import Foundation
import UIKit
import AsyncDisplayKit
import MediaPlayer
private let volumeNotificationKey = "AVSystemController_SystemVolumeDidChangeNotification"
private let volumeParameterKey = "AVSystemController_AudioVolumeNotificationParameter"
final class VolumeControlStatusBar: UIView {
private let control: MPVolumeView
private var observer: Any?
private var currentValue: Float
var valueChanged: ((Float, Float) -> Void)?
override init(frame: CGRect) {
self.control = MPVolumeView(frame: CGRect(origin: CGPoint(), size: CGSize(width: 100.0, height: 20.0)))
self.currentValue = AVAudioSession.sharedInstance().outputVolume
super.init(frame: frame)
self.addSubview(self.control)
self.observer = NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: volumeNotificationKey), object: nil, queue: OperationQueue.main, using: { [weak self] notification in
if let strongSelf = self {
if let volume = notification.userInfo?[volumeParameterKey] as? Float {
let previous = strongSelf.currentValue
strongSelf.currentValue = volume
strongSelf.valueChanged?(previous, volume)
}
}
})
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
if let observer = self.observer {
NotificationCenter.default.removeObserver(observer)
}
}
}
final class VolumeControlStatusBarNode: ASDisplayNode {
private let backgroundNode: ASImageNode
private let foregroundNode: ASImageNode
private let foregroundClippingNode: ASDisplayNode
private var validLayout: ContainerViewLayout?
var isDark: Bool = false {
didSet {
if self.isDark != oldValue {
if self.isDark {
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 4.0, color: UIColor(white: 0.6, alpha: 1.0))
self.foregroundNode.image = generateStretchableFilledCircleImage(diameter: 4.0, color: .white)
} else {
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 4.0, color: UIColor(white: 0.6, alpha: 1.0))
self.foregroundNode.image = generateStretchableFilledCircleImage(diameter: 4.0, color: .black)
}
}
}
}
private var value: CGFloat = 1.0
override init() {
self.backgroundNode = ASImageNode()
self.backgroundNode.isLayerBacked = true
self.backgroundNode.displaysAsynchronously = false
self.backgroundNode.displayWithoutProcessing = true
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 4.0, color: .gray)
self.foregroundNode = ASImageNode()
self.foregroundNode.isLayerBacked = true
self.foregroundNode.displaysAsynchronously = false
self.foregroundNode.displayWithoutProcessing = true
self.foregroundNode.image = generateStretchableFilledCircleImage(diameter: 4.0, color: .black)
self.foregroundClippingNode = ASDisplayNode()
self.foregroundClippingNode.clipsToBounds = true
self.foregroundClippingNode.addSubnode(self.foregroundNode)
super.init()
self.isUserInteractionEnabled = false
self.addSubnode(self.backgroundNode)
self.addSubnode(self.foregroundClippingNode)
}
func updateLayout(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
self.validLayout = layout
let barHeight: CGFloat = 4.0
let barWidth: CGFloat
let statusBarHeight: CGFloat
let sideInset: CGFloat
if let actual = layout.statusBarHeight {
statusBarHeight = actual
} else {
statusBarHeight = 20.0
}
if layout.safeInsets.left.isZero && layout.safeInsets.top.isZero && layout.intrinsicInsets.left.isZero && layout.intrinsicInsets.top.isZero {
sideInset = 4.0
} else {
sideInset = 12.0
}
if !layout.intrinsicInsets.bottom.isZero {
barWidth = 92.0 - sideInset * 2.0
} else {
barWidth = layout.size.width - sideInset * 2.0
}
let boundingRect = CGRect(origin: CGPoint(x: sideInset, y: floor((statusBarHeight - barHeight) / 2.0)), size: CGSize(width: barWidth, height: barHeight))
transition.updateFrame(node: self.backgroundNode, frame: boundingRect)
transition.updateFrame(node: self.foregroundNode, frame: CGRect(origin: CGPoint(), size: boundingRect.size))
transition.updateFrame(node: self.foregroundClippingNode, frame: CGRect(origin: boundingRect.origin, size: CGSize(width: self.value * boundingRect.width, height: boundingRect.height)))
}
func updateValue(from fromValue: CGFloat, to toValue: CGFloat) {
if let layout = self.validLayout {
if self.foregroundClippingNode.layer.animation(forKey: "bounds") == nil {
self.value = fromValue
self.updateLayout(layout: layout, transition: .immediate)
}
self.value = toValue
self.updateLayout(layout: layout, transition: .animated(duration: 0.25, curve: .spring))
} else {
self.value = toValue
}
}
}

View File

@ -23,50 +23,6 @@ private struct WindowLayout: Equatable {
let safeInsets: UIEdgeInsets let safeInsets: UIEdgeInsets
let onScreenNavigationHeight: CGFloat? let onScreenNavigationHeight: CGFloat?
let upperKeyboardInputPositionBound: CGFloat? let upperKeyboardInputPositionBound: CGFloat?
static func ==(lhs: WindowLayout, rhs: WindowLayout) -> Bool {
if !lhs.size.equalTo(rhs.size) {
return false
}
if let lhsStatusBarHeight = lhs.statusBarHeight {
if let rhsStatusBarHeight = rhs.statusBarHeight {
if !lhsStatusBarHeight.isEqual(to: rhsStatusBarHeight) {
return false
}
} else {
return false
}
} else if let _ = rhs.statusBarHeight {
return false
}
if lhs.forceInCallStatusBarText != rhs.forceInCallStatusBarText {
return false
}
if let lhsInputHeight = lhs.inputHeight, let rhsInputHeight = rhs.inputHeight {
if !lhsInputHeight.isEqual(to: rhsInputHeight) {
return false
}
} else if (lhs.inputHeight != nil) != (rhs.inputHeight != nil) {
return false
}
if lhs.safeInsets != rhs.safeInsets {
return false
}
if lhs.onScreenNavigationHeight != rhs.onScreenNavigationHeight {
return false
}
if lhs.upperKeyboardInputPositionBound != rhs.upperKeyboardInputPositionBound {
return false
}
return true
}
} }
private struct UpdatingLayout { private struct UpdatingLayout {
@ -337,6 +293,16 @@ private final class KeyboardGestureRecognizerDelegate: NSObject, UIGestureRecogn
} }
} }
public final class StatusBarVolumeColors {
public let background: UIColor
public let foreground: UIColor
public init(background: UIColor, foreground: UIColor) {
self.background = background
self.foreground = foreground
}
}
public class Window1 { public class Window1 {
public let hostView: WindowHostView public let hostView: WindowHostView
@ -365,6 +331,7 @@ public class Window1 {
public var previewThemeAccentColor: UIColor = .blue public var previewThemeAccentColor: UIColor = .blue
public var previewThemeDarkBlur: Bool = false public var previewThemeDarkBlur: Bool = false
public var statusBarVolumeColors: StatusBarVolumeColors = StatusBarVolumeColors(background: .lightGray, foreground: .black)
public private(set) var forceInCallStatusBarText: String? = nil public private(set) var forceInCallStatusBarText: String? = nil
public var inCallNavigate: (() -> Void)? { public var inCallNavigate: (() -> Void)? {
@ -380,13 +347,19 @@ public class Window1 {
private var keyboardTypeChangeTimer: SwiftSignalKit.Timer? private var keyboardTypeChangeTimer: SwiftSignalKit.Timer?
private let volumeControlStatusBar: VolumeControlStatusBar
private let volumeControlStatusBarNode: VolumeControlStatusBarNode
public init(hostView: WindowHostView, statusBarHost: StatusBarHost?) { public init(hostView: WindowHostView, statusBarHost: StatusBarHost?) {
self.hostView = hostView self.hostView = hostView
self.volumeControlStatusBar = VolumeControlStatusBar(frame: CGRect(origin: CGPoint(x: 0.0, y: -20.0), size: CGSize(width: 100.0, height: 20.0)))
self.volumeControlStatusBarNode = VolumeControlStatusBarNode()
self.statusBarHost = statusBarHost self.statusBarHost = statusBarHost
let statusBarHeight: CGFloat let statusBarHeight: CGFloat
if let statusBarHost = statusBarHost { if let statusBarHost = statusBarHost {
self.statusBarManager = StatusBarManager(host: statusBarHost) self.statusBarManager = StatusBarManager(host: statusBarHost, volumeControlStatusBar: self.volumeControlStatusBar, volumeControlStatusBarNode: self.volumeControlStatusBarNode)
statusBarHeight = statusBarHost.statusBarFrame.size.height statusBarHeight = statusBarHost.statusBarFrame.size.height
self.keyboardManager = KeyboardManager(host: statusBarHost) self.keyboardManager = KeyboardManager(host: statusBarHost)
} else { } else {
@ -403,6 +376,7 @@ public class Window1 {
} }
self.windowLayout = WindowLayout(size: boundsSize, metrics: layoutMetricsForScreenSize(boundsSize), statusBarHeight: statusBarHeight, forceInCallStatusBarText: self.forceInCallStatusBarText, inputHeight: 0.0, safeInsets: safeInsetsForScreenSize(boundsSize), onScreenNavigationHeight: onScreenNavigationHeight, upperKeyboardInputPositionBound: nil) self.windowLayout = WindowLayout(size: boundsSize, metrics: layoutMetricsForScreenSize(boundsSize), statusBarHeight: statusBarHeight, forceInCallStatusBarText: self.forceInCallStatusBarText, inputHeight: 0.0, safeInsets: safeInsetsForScreenSize(boundsSize), onScreenNavigationHeight: onScreenNavigationHeight, upperKeyboardInputPositionBound: nil)
self.updatingLayout = UpdatingLayout(layout: self.windowLayout, transition: .immediate)
self.presentationContext = PresentationContext() self.presentationContext = PresentationContext()
self.overlayPresentationContext = GlobalOverlayPresentationContext(statusBarHost: statusBarHost) self.overlayPresentationContext = GlobalOverlayPresentationContext(statusBarHost: statusBarHost)
@ -541,6 +515,9 @@ public class Window1 {
} }
self.windowPanRecognizer = recognizer self.windowPanRecognizer = recognizer
self.hostView.view.addGestureRecognizer(recognizer) self.hostView.view.addGestureRecognizer(recognizer)
self.hostView.view.addSubview(self.volumeControlStatusBar)
self.hostView.view.addSubview(self.volumeControlStatusBarNode.view)
} }
public required init(coder aDecoder: NSCoder) { public required init(coder aDecoder: NSCoder) {
@ -653,7 +630,7 @@ public class Window1 {
if let coveringView = self.coveringView { if let coveringView = self.coveringView {
self.hostView.view.insertSubview(rootController.view, belowSubview: coveringView) self.hostView.view.insertSubview(rootController.view, belowSubview: coveringView)
} else { } else {
self.hostView.view.addSubview(rootController.view) self.hostView.view.insertSubview(rootController.view, belowSubview: self.volumeControlStatusBarNode.view)
} }
} }
} }
@ -676,7 +653,7 @@ public class Window1 {
if let coveringView = self.coveringView { if let coveringView = self.coveringView {
self.hostView.view.insertSubview(controller.view, belowSubview: coveringView) self.hostView.view.insertSubview(controller.view, belowSubview: coveringView)
} else { } else {
self.hostView.view.addSubview(controller.view) self.hostView.view.insertSubview(controller.view, belowSubview: self.volumeControlStatusBarNode.view)
} }
} }
@ -689,7 +666,7 @@ public class Window1 {
if self.coveringView !== oldValue { if self.coveringView !== oldValue {
oldValue?.removeFromSuperview() oldValue?.removeFromSuperview()
if let coveringView = self.coveringView { if let coveringView = self.coveringView {
self.hostView.view.addSubview(coveringView) self.hostView.view.insertSubview(coveringView, belowSubview: self.volumeControlStatusBarNode.view)
if !self.windowLayout.size.width.isZero { if !self.windowLayout.size.width.isZero {
coveringView.frame = CGRect(origin: CGPoint(), size: self.windowLayout.size) coveringView.frame = CGRect(origin: CGPoint(), size: self.windowLayout.size)
coveringView.updateLayout(self.windowLayout.size) coveringView.updateLayout(self.windowLayout.size)
@ -813,10 +790,13 @@ public class Window1 {
} }
} }
private var isFirstLayout = true
private func commitUpdatingLayout() { private func commitUpdatingLayout() {
if let updatingLayout = self.updatingLayout { if let updatingLayout = self.updatingLayout {
self.updatingLayout = nil self.updatingLayout = nil
if updatingLayout.layout != self.windowLayout { if updatingLayout.layout != self.windowLayout || self.isFirstLayout {
self.isFirstLayout = false
var statusBarHeight: CGFloat? var statusBarHeight: CGFloat?
if let statusBarHost = self.statusBarHost { if let statusBarHost = self.statusBarHost {
statusBarHeight = statusBarHost.statusBarFrame.size.height statusBarHeight = statusBarHost.statusBarFrame.size.height
@ -864,6 +844,9 @@ public class Window1 {
}) })
} }
self.volumeControlStatusBarNode.frame = CGRect(origin: CGPoint(), size: self.windowLayout.size)
self.volumeControlStatusBarNode.updateLayout(layout: childLayout, transition: updatingLayout.transition)
if let coveringView = self.coveringView { if let coveringView = self.coveringView {
coveringView.frame = CGRect(origin: CGPoint(), size: self.windowLayout.size) coveringView.frame = CGRect(origin: CGPoint(), size: self.windowLayout.size)
coveringView.updateLayout(self.windowLayout.size) coveringView.updateLayout(self.windowLayout.size)

View File

@ -20,22 +20,6 @@ public struct UIEdgeInsets: Equatable {
self.bottom = bottom self.bottom = bottom
self.right = right self.right = right
} }
public static func ==(lhs: UIEdgeInsets, rhs: UIEdgeInsets) -> Bool {
if !lhs.top.isEqual(to: rhs.top) {
return false
}
if !lhs.left.isEqual(to: rhs.left) {
return false
}
if !lhs.bottom.isEqual(to: rhs.bottom) {
return false
}
if !lhs.right.isEqual(to: rhs.right) {
return false
}
return true
}
} }
public final class UIColor: NSObject { public final class UIColor: NSObject {