This commit is contained in:
Peter 2019-10-03 04:11:41 +04:00
parent 5da7197c55
commit bb9b706c94
44 changed files with 781 additions and 175 deletions

View File

@ -168,6 +168,28 @@ package_arm64:
PACKAGE_BUNDLE_ID="${BUNDLE_ID}" \ PACKAGE_BUNDLE_ID="${BUNDLE_ID}" \
sh package_app.sh iphoneos-arm64 $(BUCK) $(BUCK_OPTIONS) ${BUCK_RELEASE_OPTIONS} sh package_app.sh iphoneos-arm64 $(BUCK) $(BUCK_OPTIONS) ${BUCK_RELEASE_OPTIONS}
package_debug_arm64:
PACKAGE_DEVELOPMENT_TEAM="${DEVELOPMENT_TEAM}" \
PACKAGE_CODE_SIGN_IDENTITY="${DEVELOPMENT_CODE_SIGN_IDENTITY}" \
PACKAGE_PROVISIONING_PROFILE_APP="${DEVELOPMENT_PROVISIONING_PROFILE_APP}" \
PACKAGE_ENTITLEMENTS_APP="${ENTITLEMENTS_APP}" \
PACKAGE_PROVISIONING_PROFILE_EXTENSION_Share="${DEVELOPMENT_PROVISIONING_PROFILE_EXTENSION_SHARE}" \
PACKAGE_ENTITLEMENTS_EXTENSION_Share="${ENTITLEMENTS_EXTENSION_SHARE}" \
PACKAGE_PROVISIONING_PROFILE_EXTENSION_Widget="${DEVELOPMENT_PROVISIONING_PROFILE_EXTENSION_WIDGET}" \
PACKAGE_ENTITLEMENTS_EXTENSION_Widget="${ENTITLEMENTS_EXTENSION_WIDGET}" \
PACKAGE_PROVISIONING_PROFILE_EXTENSION_NotificationService="${DEVELOPMENT_PROVISIONING_PROFILE_EXTENSION_NOTIFICATIONSERVICE}" \
PACKAGE_ENTITLEMENTS_EXTENSION_NotificationService="${ENTITLEMENTS_EXTENSION_NOTIFICATIONSERVICE}" \
PACKAGE_PROVISIONING_PROFILE_EXTENSION_NotificationContent="${DEVELOPMENT_PROVISIONING_PROFILE_EXTENSION_NOTIFICATIONCONTENT}" \
PACKAGE_ENTITLEMENTS_EXTENSION_NotificationContent="${ENTITLEMENTS_EXTENSION_NOTIFICATIONCONTENT}" \
PACKAGE_PROVISIONING_PROFILE_EXTENSION_Intents="${DEVELOPMENT_PROVISIONING_PROFILE_EXTENSION_INTENTS}" \
PACKAGE_ENTITLEMENTS_EXTENSION_Intents="${ENTITLEMENTS_EXTENSION_INTENTS}" \
PACKAGE_PROVISIONING_PROFILE_WATCH_APP="${DEVELOPMENT_PROVISIONING_PROFILE_WATCH_APP}" \
PACKAGE_PROVISIONING_PROFILE_WATCH_EXTENSION="${DISTRIBUTION_PROVISIONING_PROFILE_WATCH_EXTENSION}" \
PACKAGE_BUNDLE_ID="${BUNDLE_ID}" \
ENABLE_GET_TASK_ALLOW=1 \
CODESIGNING_PROFILES_VARIANT="development" \
sh package_app.sh iphoneos-arm64 $(BUCK) $(BUCK_OPTIONS) ${BUCK_RELEASE_OPTIONS}
package: package:
PACKAGE_DEVELOPMENT_TEAM="${DEVELOPMENT_TEAM}" \ PACKAGE_DEVELOPMENT_TEAM="${DEVELOPMENT_TEAM}" \
PACKAGE_CODE_SIGN_IDENTITY="${DISTRIBUTION_CODE_SIGN_IDENTITY}" \ PACKAGE_CODE_SIGN_IDENTITY="${DISTRIBUTION_CODE_SIGN_IDENTITY}" \
@ -192,7 +214,7 @@ app: build package
app_arm64: build_arm64 package_arm64 app_arm64: build_arm64 package_arm64
app_debug_arm64: build_debug_arm64 package_arm64 app_debug_arm64: build_debug_arm64 package_debug_arm64
build_buckdebug: check_env build_buckdebug: check_env
BUCK_DEBUG_MODE=1 $(BUCK) build \ BUCK_DEBUG_MODE=1 $(BUCK) build \

View File

@ -301,6 +301,11 @@
<string>remote-notification</string> <string>remote-notification</string>
<string>voip</string> <string>voip</string>
</array> </array>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIFileSharingEnabled</key> <key>UIFileSharingEnabled</key>
<false/> <false/>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
@ -356,10 +361,5 @@
</dict> </dict>
</dict> </dict>
</array> </array>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
</dict> </dict>
</plist> </plist>

View File

@ -44,6 +44,8 @@
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Debug"
@ -65,6 +67,8 @@
ReferencedContainer = "container:Project.xcodeproj"> ReferencedContainer = "container:Project.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release" buildConfiguration = "Release"

View File

@ -44,6 +44,8 @@
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Debug"
@ -65,6 +67,8 @@
ReferencedContainer = "container:Project.xcodeproj"> ReferencedContainer = "container:Project.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release" buildConfiguration = "Release"

View File

@ -44,6 +44,8 @@
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Debug"
@ -65,6 +67,8 @@
ReferencedContainer = "container:Project.xcodeproj"> ReferencedContainer = "container:Project.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release" buildConfiguration = "Release"

View File

@ -44,6 +44,8 @@
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Debug"
@ -65,6 +67,8 @@
ReferencedContainer = "container:Project.xcodeproj"> ReferencedContainer = "container:Project.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release" buildConfiguration = "Release"

View File

@ -44,6 +44,8 @@
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Debug"
@ -65,6 +67,8 @@
ReferencedContainer = "container:Project.xcodeproj"> ReferencedContainer = "container:Project.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release" buildConfiguration = "Release"

View File

@ -2563,6 +2563,8 @@
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Debug"
@ -2572,6 +2574,8 @@
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES"
stopOnEveryThreadSanitizerIssue = "YES"
stopOnEveryMainThreadCheckerIssue = "YES"
debugServiceExtension = "internal" debugServiceExtension = "internal"
allowLocationSimulation = "YES"> allowLocationSimulation = "YES">
<BuildableProductRunnable <BuildableProductRunnable
@ -2584,6 +2588,8 @@
ReferencedContainer = "container:Project.xcodeproj"> ReferencedContainer = "container:Project.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release" buildConfiguration = "Release"

View File

@ -184,6 +184,12 @@ for ITEM in $APP_ITEMS_WITH_PROVISIONING_PROFILE; do
fi fi
done done
if [ "$ENABLE_GET_TASK_ALLOW" == "1" ]; then
KEY="com.apple.security.get-task-allow"
PLUTIL_KEY=$(echo "$KEY" | sed 's/\./\\\./g')
plutil -insert "$PLUTIL_KEY" -xml "<false/>" "$PROFILE_ENTITLEMENTS_PATH"
fi
ENTITLEMENTS_VAR=PACKAGE_ENTITLEMENTS_$ITEM ENTITLEMENTS_VAR=PACKAGE_ENTITLEMENTS_$ITEM
if [ ! -z "${!ENTITLEMENTS_VAR}" ]; then if [ ! -z "${!ENTITLEMENTS_VAR}" ]; then
if [ ! -f "${!ENTITLEMENTS_VAR}" ]; then if [ ! -f "${!ENTITLEMENTS_VAR}" ]; then

View File

@ -24,6 +24,6 @@
+ (void)getHardwareEncryptionAvailableWithBaseAppBundleId:(NSString * _Nonnull)baseAppBundleId completion:(void (^)(NSData * _Nullable))completion; + (void)getHardwareEncryptionAvailableWithBaseAppBundleId:(NSString * _Nonnull)baseAppBundleId completion:(void (^)(NSData * _Nullable))completion;
+ (void)encryptApplicationSecret:(NSData * _Nonnull)secret baseAppBundleId:(NSString * _Nonnull)baseAppBundleId completion:(void (^)(NSData * _Nullable, NSData * _Nullable))completion; + (void)encryptApplicationSecret:(NSData * _Nonnull)secret baseAppBundleId:(NSString * _Nonnull)baseAppBundleId completion:(void (^)(NSData * _Nullable, NSData * _Nullable))completion;
+ (void)decryptApplicationSecret:(NSData * _Nonnull)secret publicKey:(NSData * _Nonnull)publicKey baseAppBundleId:(NSString * _Nonnull)baseAppBundleId completion:(void (^)(NSData * _Nullable))completion; + (void)decryptApplicationSecret:(NSData * _Nonnull)secret publicKey:(NSData * _Nonnull)publicKey baseAppBundleId:(NSString * _Nonnull)baseAppBundleId completion:(void (^)(NSData * _Nullable, bool))completion;
@end @end

View File

@ -694,28 +694,29 @@ API_AVAILABLE(ios(10))
}); });
} }
+ (void)decryptApplicationSecret:(NSData * _Nonnull)secret publicKey:(NSData * _Nonnull)publicKey baseAppBundleId:(NSString * _Nonnull)baseAppBundleId completion:(void (^)(NSData * _Nullable))completion { + (void)decryptApplicationSecret:(NSData * _Nonnull)secret publicKey:(NSData * _Nonnull)publicKey baseAppBundleId:(NSString * _Nonnull)baseAppBundleId completion:(void (^)(NSData * _Nullable, bool))completion {
dispatch_async([self encryptionQueue], ^{ dispatch_async([self encryptionQueue], ^{
LocalPrivateKey *privateKey = [self getApplicationSecretKey:baseAppBundleId isCheckKey:false]; LocalPrivateKey *privateKey = [self getApplicationSecretKey:baseAppBundleId isCheckKey:false];
if (privateKey == nil) { if (privateKey == nil) {
completion(nil); completion(nil, false);
return; return;
} }
if (privateKey == nil) { if (privateKey == nil) {
completion(nil); completion(nil, false);
return; return;
} }
NSData *currentPublicKey = [privateKey getPublicKey]; NSData *currentPublicKey = [privateKey getPublicKey];
if (currentPublicKey == nil) { if (currentPublicKey == nil) {
completion(nil); completion(nil, false);
return; return;
} }
if (![publicKey isEqualToData:currentPublicKey]) { if (![publicKey isEqualToData:currentPublicKey]) {
completion(nil); completion(nil, false);
return; return;
} }
NSData *result = [privateKey decrypt:secret cancelled:nil]; bool cancelled = false;
completion(result); NSData *result = [privateKey decrypt:secret cancelled:&cancelled];
completion(result, cancelled);
}); });
} }

View File

@ -57,6 +57,8 @@ public final class ContextGesture: UIGestureRecognizer, UIGestureRecognizerDeleg
override public func reset() { override public func reset() {
super.reset() super.reset()
self.endPressedAppearance()
self.currentProgress = 0.0 self.currentProgress = 0.0
self.delayTimer?.invalidate() self.delayTimer?.invalidate()
self.delayTimer = nil self.delayTimer = nil
@ -152,9 +154,8 @@ public final class ContextGesture: UIGestureRecognizer, UIGestureRecognizerDeleg
if let touch = touches.first { if let touch = touches.first {
if !self.currentProgress.isZero, self.isValidated { if !self.currentProgress.isZero, self.isValidated {
if #available(iOS 9.0, *) { self.currentProgress = 0.0
self.activationProgress?(0.0, .ended(self.currentProgress)) self.activationProgress?(0.0, .ended(self.currentProgress))
}
} }
self.externalEnded?((self.view, touch.location(in: self.view))) self.externalEnded?((self.view, touch.location(in: self.view)))
@ -170,9 +171,8 @@ public final class ContextGesture: UIGestureRecognizer, UIGestureRecognizerDeleg
super.touchesCancelled(touches, with: event) super.touchesCancelled(touches, with: event)
if let touch = touches.first, !self.currentProgress.isZero, self.isValidated { if let touch = touches.first, !self.currentProgress.isZero, self.isValidated {
if #available(iOS 9.0, *) { self.currentProgress = 0.0
self.activationProgress?(0.0, .ended(self.currentProgress)) self.activationProgress?(0.0, .ended(self.currentProgress))
}
} }
self.delayTimer?.invalidate() self.delayTimer?.invalidate()
@ -183,6 +183,7 @@ public final class ContextGesture: UIGestureRecognizer, UIGestureRecognizerDeleg
public func cancel() { public func cancel() {
if !self.currentProgress.isZero, self.isValidated { if !self.currentProgress.isZero, self.isValidated {
self.currentProgress = 0.0
self.activationProgress?(0.0, .ended(self.currentProgress)) self.activationProgress?(0.0, .ended(self.currentProgress))
self.delayTimer?.invalidate() self.delayTimer?.invalidate()

View File

@ -95,10 +95,8 @@ final class GlobalOverlayPresentationContext {
} }
return keyboardWindow return keyboardWindow
} else { } else {
if underStatusBar, let view = self.parentView { if let view = self.parentView {
return view return view
} else {
return statusBarHost.statusBarWindow
} }
} }
} }

View File

@ -3313,6 +3313,10 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
indicatorFrame.origin.y = self.visibleSize.height - (self.scrollIndicatorInsets.bottom + indicatorBottomInset) - indicatorFrame.height indicatorFrame.origin.y = self.visibleSize.height - (self.scrollIndicatorInsets.bottom + indicatorBottomInset) - indicatorFrame.height
} }
if indicatorFrame.origin.y.isNaN {
indicatorFrame.origin.y = indicatorTopInset
}
if indicatorHeight >= visibleHeightWithoutIndicatorInsets { if indicatorHeight >= visibleHeightWithoutIndicatorInsets {
verticalScrollIndicator.isHidden = true verticalScrollIndicator.isHidden = true
verticalScrollIndicator.frame = indicatorFrame verticalScrollIndicator.frame = indicatorFrame

View File

@ -76,13 +76,22 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate {
private(set) var controllers: [ViewController] = [] private(set) var controllers: [ViewController] = []
private var state: State = State(layout: nil, canBeClosed: nil, top: nil, transition: nil, pending: nil) private var state: State = State(layout: nil, canBeClosed: nil, top: nil, transition: nil, pending: nil)
private var ignoreInputHeight: Bool = false
private(set) var isReady: Bool = false private(set) var isReady: Bool = false
var isReadyUpdated: (() -> Void)? var isReadyUpdated: (() -> Void)?
var controllerRemoved: (ViewController) -> Void var controllerRemoved: (ViewController) -> Void
var keyboardViewManager: KeyboardViewManager? { var keyboardViewManager: KeyboardViewManager? {
didSet { didSet {
if self.keyboardViewManager !== oldValue { }
}
var canHaveKeyboardFocus: Bool = false {
didSet {
if self.canHaveKeyboardFocus != oldValue {
if !self.canHaveKeyboardFocus {
self.view.endEditing(true)
self.performUpdate(transition: .animated(duration: 0.5, curve: .spring))
}
} }
} }
} }
@ -147,6 +156,7 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate {
guard self.state.transition == nil else { guard self.state.transition == nil else {
return return
} }
let beginGesture = self.controllers.count > 1 let beginGesture = self.controllers.count > 1
if beginGesture { if beginGesture {
@ -163,7 +173,7 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate {
topController.viewWillDisappear(true) topController.viewWillDisappear(true)
let topNode = topController.displayNode let topNode = topController.displayNode
bottomController.containerLayoutUpdated(layout, transition: .immediate) bottomController.containerLayoutUpdated(layout.withUpdatedInputHeight(nil), transition: .immediate)
bottomController.viewWillAppear(true) bottomController.viewWillAppear(true)
let bottomNode = bottomController.displayNode let bottomNode = bottomController.displayNode
@ -195,11 +205,16 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate {
let topController = top.value let topController = top.value
let bottomController = transition.previous.value let bottomController = transition.previous.value
if viewTreeContainsFirstResponder(view: top.value.view) {
strongSelf.ignoreInputHeight = true
}
strongSelf.keyboardViewManager?.dismissEditingWithoutAnimation(view: topController.view) strongSelf.keyboardViewManager?.dismissEditingWithoutAnimation(view: topController.view)
strongSelf.state.transition = nil strongSelf.state.transition = nil
strongSelf.controllerRemoved(top.value) strongSelf.controllerRemoved(top.value)
strongSelf.ignoreInputHeight = false
}) })
} else { } else {
navigationTransitionCoordinator.animateCancel({ [weak self] in navigationTransitionCoordinator.animateCancel({ [weak self] in
@ -383,12 +398,16 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate {
} }
private func makeChild(layout: ContainerViewLayout, value: ViewController) -> Child { private func makeChild(layout: ContainerViewLayout, value: ViewController) -> Child {
value.containerLayoutUpdated(layout, transition: .immediate) let updatedLayout = layout.withUpdatedInputHeight(nil)
return Child(value: value, layout: layout) value.containerLayoutUpdated(updatedLayout, transition: .immediate)
return Child(value: value, layout: updatedLayout)
} }
private func applyLayout(layout: ContainerViewLayout, to child: Child, isMaster: Bool, transition: ContainedViewLayoutTransition) { private func applyLayout(layout: ContainerViewLayout, to child: Child, isMaster: Bool, transition: ContainedViewLayoutTransition) {
var childFrame = CGRect(origin: CGPoint(), size: layout.size) var childFrame = CGRect(origin: CGPoint(), size: layout.size)
var updatedLayout = layout
var shouldSyncKeyboard = false var shouldSyncKeyboard = false
if let transition = self.state.transition { if let transition = self.state.transition {
childFrame.origin.x = child.value.displayNode.frame.origin.x childFrame.origin.x = child.value.displayNode.frame.origin.x
@ -400,10 +419,21 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate {
case .push: case .push:
break break
} }
if updatedLayout.inputHeight != nil {
if !self.canHaveKeyboardFocus {
updatedLayout = updatedLayout.withUpdatedInputHeight(nil)
}
}
} else { } else {
if isMaster { if isMaster {
shouldSyncKeyboard = true shouldSyncKeyboard = true
} }
if updatedLayout.inputHeight != nil {
if !self.canHaveKeyboardFocus || self.ignoreInputHeight {
updatedLayout = updatedLayout.withUpdatedInputHeight(nil)
}
}
} }
if child.value.displayNode.frame != childFrame { if child.value.displayNode.frame != childFrame {
transition.updateFrame(node: child.value.displayNode, frame: childFrame) transition.updateFrame(node: child.value.displayNode, frame: childFrame)
@ -411,9 +441,9 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate {
if shouldSyncKeyboard && isMaster { if shouldSyncKeyboard && isMaster {
self.syncKeyboard(leftEdge: childFrame.minX, transition: transition) self.syncKeyboard(leftEdge: childFrame.minX, transition: transition)
} }
if child.layout != layout { if child.layout != updatedLayout {
child.layout = layout child.layout = updatedLayout
child.value.containerLayoutUpdated(layout, transition: transition) child.value.containerLayoutUpdated(updatedLayout, transition: transition)
} }
} }
@ -430,13 +460,13 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate {
private func pendingChildIsReady(_ child: PendingChild) { private func pendingChildIsReady(_ child: PendingChild) {
if let pending = self.state.pending, pending === child { if let pending = self.state.pending, pending === child {
pending.isReady = true pending.isReady = true
self.performUpdate() self.performUpdate(transition: .immediate)
} }
} }
private func performUpdate() { private func performUpdate(transition: ContainedViewLayoutTransition) {
if let layout = self.state.layout, let canBeClosed = self.state.canBeClosed { if let layout = self.state.layout, let canBeClosed = self.state.canBeClosed {
self.update(layout: layout, canBeClosed: canBeClosed, controllers: self.controllers, transition: .immediate) self.update(layout: layout, canBeClosed: canBeClosed, controllers: self.controllers, transition: transition)
} }
} }

View File

@ -118,12 +118,18 @@ open class NavigationController: UINavigationController, ContainableController,
return self.view as! NavigationControllerView return self.view as! NavigationControllerView
} }
var inCallNavigate: (() -> Void)?
private var inCallStatusBar: StatusBar? private var inCallStatusBar: StatusBar?
private var globalScrollToTopNode: ScrollToTopNode?
private var rootContainer: RootContainer? private var rootContainer: RootContainer?
private var rootModalFrame: NavigationModalFrame? private var rootModalFrame: NavigationModalFrame?
private var modalContainers: [NavigationModalContainer] = [] private var modalContainers: [NavigationModalContainer] = []
private var overlayContainers: [NavigationOverlayContainer] = []
private var validLayout: ContainerViewLayout? private var validLayout: ContainerViewLayout?
private var validStatusBarStyle: NavigationStatusBarStyle? private var validStatusBarStyle: NavigationStatusBarStyle?
private var validStatusBarHidden: Bool = false
private var currentStatusBarExternalHidden: Bool = false
private var scheduledLayoutTransitionRequestId: Int = 0 private var scheduledLayoutTransitionRequestId: Int = 0
private var scheduledLayoutTransitionRequest: (Int, ContainedViewLayoutTransition)? private var scheduledLayoutTransitionRequest: (Int, ContainedViewLayoutTransition)?
@ -151,7 +157,10 @@ open class NavigationController: UINavigationController, ContainableController,
return self._displayNode! return self._displayNode!
} }
var statusBarHost: StatusBarHost? var statusBarHost: StatusBarHost? {
didSet {
}
}
var keyboardViewManager: KeyboardViewManager? var keyboardViewManager: KeyboardViewManager?
public func updateMasterDetailsBlackout(_ blackout: MasterDetailLayoutBlackout?, transition: ContainedViewLayoutTransition) { public func updateMasterDetailsBlackout(_ blackout: MasterDetailLayoutBlackout?, transition: ContainedViewLayoutTransition) {
@ -199,6 +208,9 @@ open class NavigationController: UINavigationController, ContainableController,
for modalContainer in self.modalContainers { for modalContainer in self.modalContainers {
supportedOrientations = supportedOrientations.intersection(modalContainer.container.combinedSupportedOrientations(currentOrientationToLock: currentOrientationToLock)) supportedOrientations = supportedOrientations.intersection(modalContainer.container.combinedSupportedOrientations(currentOrientationToLock: currentOrientationToLock))
} }
for overlayContrainer in self.overlayContainers {
supportedOrientations = supportedOrientations.intersection(overlayContrainer.controller.combinedSupportedOrientations(currentOrientationToLock: currentOrientationToLock))
}
return supportedOrientations return supportedOrientations
} }
@ -214,18 +226,10 @@ open class NavigationController: UINavigationController, ContainableController,
} }
} }
if self.isViewLoaded { if self.isViewLoaded {
if statusBarStyleUpdated {
self.validStatusBarStyle = self.theme.statusBar
let normalStatusBarStyle: UIStatusBarStyle
switch self.theme.statusBar {
case .black:
normalStatusBarStyle = .default
case .white:
normalStatusBarStyle = .lightContent
}
//self.statusBarHost?.setStatusBarStyle(normalStatusBarStyle, animated: false)
}
self.controllerView.backgroundColor = theme.emptyAreaColor self.controllerView.backgroundColor = theme.emptyAreaColor
if let layout = self.validLayout {
self.containerLayoutUpdated(layout, transition: .immediate)
}
} }
} }
@ -239,16 +243,33 @@ open class NavigationController: UINavigationController, ContainableController,
} }
self.validLayout = layout self.validLayout = layout
self.updateContainers(layout: layout, transition: transition) self.updateContainers(layout: layout, transition: transition)
self.inCallStatusBar?.frame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: max(40.0, layout.safeInsets.top)))
self.inCallStatusBar?.updateState(statusBar: nil, withSafeInsets: false, inCallText: "In Call Text", animated: false)
} }
private func updateContainers(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { private weak var currentTopVisibleOverlayContainerStatusBar: NavigationOverlayContainer? = nil
private func updateContainers(layout rawLayout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
var layout = rawLayout
if let globalScrollToTopNode = self.globalScrollToTopNode {
globalScrollToTopNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -1.0), size: CGSize(width: layout.size.width, height: 1.0))
}
if let inCallStatusBar = self.inCallStatusBar {
let inCallStatusBarFrame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: max(40.0, layout.safeInsets.top)))
if inCallStatusBar.frame.isEmpty {
inCallStatusBar.frame = inCallStatusBarFrame
} else {
transition.updateFrame(node: inCallStatusBar, frame: inCallStatusBarFrame)
}
layout.statusBarHeight = inCallStatusBarFrame.height
self.inCallStatusBar?.frame = inCallStatusBarFrame
}
let navigationLayout = makeNavigationLayout(mode: self.mode, layout: layout, controllers: self._viewControllers) let navigationLayout = makeNavigationLayout(mode: self.mode, layout: layout, controllers: self._viewControllers)
var transition = transition var transition = transition
var statusBarStyle: StatusBarStyle = .Ignore var statusBarStyle: StatusBarStyle = .Ignore
var statusBarHidden = false
var animateStatusBarStyleTransition = transition.isAnimated var animateStatusBarStyleTransition = transition.isAnimated
var modalContainers: [NavigationModalContainer] = [] var modalContainers: [NavigationModalContainer] = []
@ -311,6 +332,56 @@ open class NavigationController: UINavigationController, ContainableController,
} }
self.modalContainers = modalContainers self.modalContainers = modalContainers
var previousOverlayContainer: NavigationOverlayContainer?
var topVisibleOverlayContainerWithStatusBar: NavigationOverlayContainer?
for i in (0 ..< self.overlayContainers.count).reversed() {
let overlayContainer = self.overlayContainers[i]
let containerTransition: ContainedViewLayoutTransition
if overlayContainer.supernode == nil {
containerTransition = .immediate
} else {
containerTransition = transition
}
containerTransition.updateFrame(node: overlayContainer, frame: CGRect(origin: CGPoint(), size: layout.size))
overlayContainer.update(layout: layout, transition: containerTransition)
if overlayContainer.supernode == nil && overlayContainer.isReady {
if let previousOverlayContainer = previousOverlayContainer {
self.displayNode.insertSubnode(overlayContainer, belowSubnode: previousOverlayContainer)
} else if let globalScrollToTopNode = self.globalScrollToTopNode {
self.displayNode.insertSubnode(overlayContainer, belowSubnode: globalScrollToTopNode)
} else {
self.displayNode.addSubnode(overlayContainer)
}
overlayContainer.transitionIn()
}
if overlayContainer.supernode != nil {
previousOverlayContainer = overlayContainer
let controllerStatusBarStyle = overlayContainer.controller.statusBar.statusBarStyle
switch controllerStatusBarStyle {
case .Black, .White, .Hide:
if topVisibleOverlayContainerWithStatusBar == nil {
topVisibleOverlayContainerWithStatusBar = overlayContainer
}
if case .Hide = controllerStatusBarStyle {
statusBarHidden = true
} else {
statusBarHidden = overlayContainer.controller.statusBar.alpha.isZero
}
case .Ignore:
break
}
}
}
if self.currentTopVisibleOverlayContainerStatusBar !== topVisibleOverlayContainerWithStatusBar {
self.currentTopVisibleOverlayContainerStatusBar = topVisibleOverlayContainerWithStatusBar
animateStatusBarStyleTransition = true
}
var previousModalContainer: NavigationModalContainer? var previousModalContainer: NavigationModalContainer?
var visibleModalCount = 0 var visibleModalCount = 0
var topModalDismissProgress: CGFloat = 0.0 var topModalDismissProgress: CGFloat = 0.0
@ -342,6 +413,10 @@ open class NavigationController: UINavigationController, ContainableController,
self.displayNode.insertSubnode(modalContainer, belowSubnode: previousModalContainer) self.displayNode.insertSubnode(modalContainer, belowSubnode: previousModalContainer)
} else if let inCallStatusBar = self.inCallStatusBar { } else if let inCallStatusBar = self.inCallStatusBar {
self.displayNode.insertSubnode(modalContainer, belowSubnode: inCallStatusBar) self.displayNode.insertSubnode(modalContainer, belowSubnode: inCallStatusBar)
} else if let previousOverlayContainer = previousOverlayContainer {
self.displayNode.insertSubnode(modalContainer, belowSubnode: previousOverlayContainer)
} else if let globalScrollToTopNode = self.globalScrollToTopNode {
self.displayNode.insertSubnode(modalContainer, belowSubnode: globalScrollToTopNode)
} else { } else {
self.displayNode.addSubnode(modalContainer) self.displayNode.addSubnode(modalContainer)
} }
@ -354,11 +429,14 @@ open class NavigationController: UINavigationController, ContainableController,
topModalDismissProgress = modalContainer.dismissProgress topModalDismissProgress = modalContainer.dismissProgress
if case .compact = layout.metrics.widthClass { if case .compact = layout.metrics.widthClass {
modalContainer.keyboardViewManager = self.keyboardViewManager modalContainer.keyboardViewManager = self.keyboardViewManager
modalContainer.canHaveKeyboardFocus = true
} else { } else {
modalContainer.keyboardViewManager = nil modalContainer.keyboardViewManager = nil
modalContainer.canHaveKeyboardFocus = true
} }
} else { } else {
modalContainer.keyboardViewManager = nil modalContainer.keyboardViewManager = nil
modalContainer.canHaveKeyboardFocus = false
} }
previousModalContainer = modalContainer previousModalContainer = modalContainer
} }
@ -371,8 +449,10 @@ open class NavigationController: UINavigationController, ContainableController,
case let .flat(flatContainer): case let .flat(flatContainer):
if previousModalContainer == nil { if previousModalContainer == nil {
flatContainer.keyboardViewManager = self.keyboardViewManager flatContainer.keyboardViewManager = self.keyboardViewManager
flatContainer.canHaveKeyboardFocus = true
} else { } else {
flatContainer.keyboardViewManager = nil flatContainer.keyboardViewManager = nil
flatContainer.canHaveKeyboardFocus = false
} }
transition.updateFrame(node: flatContainer, frame: CGRect(origin: CGPoint(), size: layout.size)) transition.updateFrame(node: flatContainer, frame: CGRect(origin: CGPoint(), size: layout.size))
flatContainer.update(layout: layout, canBeClosed: false, controllers: controllers, transition: transition) flatContainer.update(layout: layout, canBeClosed: false, controllers: controllers, transition: transition)
@ -386,6 +466,13 @@ open class NavigationController: UINavigationController, ContainableController,
} }
strongSelf.updateContainers(layout: layout, transition: transition) strongSelf.updateContainers(layout: layout, transition: transition)
} }
if previousModalContainer == nil {
flatContainer.keyboardViewManager = self.keyboardViewManager
flatContainer.canHaveKeyboardFocus = true
} else {
flatContainer.keyboardViewManager = nil
flatContainer.canHaveKeyboardFocus = false
}
self.displayNode.insertSubnode(flatContainer, at: 0) self.displayNode.insertSubnode(flatContainer, at: 0)
self.rootContainer = .flat(flatContainer) self.rootContainer = .flat(flatContainer)
flatContainer.frame = CGRect(origin: CGPoint(), size: layout.size) flatContainer.frame = CGRect(origin: CGPoint(), size: layout.size)
@ -402,6 +489,13 @@ open class NavigationController: UINavigationController, ContainableController,
} }
strongSelf.updateContainers(layout: layout, transition: transition) strongSelf.updateContainers(layout: layout, transition: transition)
} }
if previousModalContainer == nil {
flatContainer.keyboardViewManager = self.keyboardViewManager
flatContainer.canHaveKeyboardFocus = true
} else {
flatContainer.keyboardViewManager = nil
flatContainer.canHaveKeyboardFocus = false
}
self.displayNode.insertSubnode(flatContainer, at: 0) self.displayNode.insertSubnode(flatContainer, at: 0)
self.rootContainer = .flat(flatContainer) self.rootContainer = .flat(flatContainer)
flatContainer.frame = CGRect(origin: CGPoint(), size: layout.size) flatContainer.frame = CGRect(origin: CGPoint(), size: layout.size)
@ -413,23 +507,42 @@ open class NavigationController: UINavigationController, ContainableController,
case let .flat(flatContainer): case let .flat(flatContainer):
let splitContainer = NavigationSplitContainer(theme: self.theme, controllerRemoved: { [weak self] controller in let splitContainer = NavigationSplitContainer(theme: self.theme, controllerRemoved: { [weak self] controller in
self?.controllerRemoved(controller) self?.controllerRemoved(controller)
}, scrollToTop: { [weak self] subject in
self?.scrollToTop(subject)
}) })
self.displayNode.insertSubnode(splitContainer, at: 0) self.displayNode.insertSubnode(splitContainer, at: 0)
self.rootContainer = .split(splitContainer) self.rootContainer = .split(splitContainer)
if previousModalContainer == nil {
splitContainer.canHaveKeyboardFocus = true
} else {
splitContainer.canHaveKeyboardFocus = false
}
splitContainer.frame = CGRect(origin: CGPoint(), size: layout.size) splitContainer.frame = CGRect(origin: CGPoint(), size: layout.size)
splitContainer.update(layout: layout, masterControllers: masterControllers, detailControllers: detailControllers, transition: .immediate) splitContainer.update(layout: layout, masterControllers: masterControllers, detailControllers: detailControllers, transition: .immediate)
flatContainer.statusBarStyleUpdated = nil flatContainer.statusBarStyleUpdated = nil
flatContainer.removeFromSupernode() flatContainer.removeFromSupernode()
case let .split(splitContainer): case let .split(splitContainer):
if previousModalContainer == nil {
splitContainer.canHaveKeyboardFocus = true
} else {
splitContainer.canHaveKeyboardFocus = false
}
transition.updateFrame(node: splitContainer, frame: CGRect(origin: CGPoint(), size: layout.size)) transition.updateFrame(node: splitContainer, frame: CGRect(origin: CGPoint(), size: layout.size))
splitContainer.update(layout: layout, masterControllers: masterControllers, detailControllers: detailControllers, transition: transition) splitContainer.update(layout: layout, masterControllers: masterControllers, detailControllers: detailControllers, transition: transition)
} }
} else { } else {
let splitContainer = NavigationSplitContainer(theme: self.theme, controllerRemoved: { [weak self] controller in let splitContainer = NavigationSplitContainer(theme: self.theme, controllerRemoved: { [weak self] controller in
self?.controllerRemoved(controller) self?.controllerRemoved(controller)
}, scrollToTop: { [weak self] subject in
self?.scrollToTop(subject)
}) })
self.displayNode.insertSubnode(splitContainer, at: 0) self.displayNode.insertSubnode(splitContainer, at: 0)
self.rootContainer = .split(splitContainer) self.rootContainer = .split(splitContainer)
if previousModalContainer == nil {
splitContainer.canHaveKeyboardFocus = true
} else {
splitContainer.canHaveKeyboardFocus = false
}
splitContainer.frame = CGRect(origin: CGPoint(), size: layout.size) splitContainer.frame = CGRect(origin: CGPoint(), size: layout.size)
splitContainer.update(layout: layout, masterControllers: masterControllers, detailControllers: detailControllers, transition: .immediate) splitContainer.update(layout: layout, masterControllers: masterControllers, detailControllers: detailControllers, transition: .immediate)
} }
@ -439,8 +552,9 @@ open class NavigationController: UINavigationController, ContainableController,
switch rootContainer { switch rootContainer {
case let .flat(container): case let .flat(container):
statusBarStyle = container.statusBarStyle statusBarStyle = container.statusBarStyle
self.globalScrollToTopNode?.isHidden = false
case .split: case .split:
break self.globalScrollToTopNode?.isHidden = true
} }
} }
@ -559,6 +673,18 @@ open class NavigationController: UINavigationController, ContainableController,
} }
} }
if self.inCallStatusBar != nil {
statusBarStyle = .White
}
if let topVisibleOverlayContainerWithStatusBar = topVisibleOverlayContainerWithStatusBar {
statusBarStyle = topVisibleOverlayContainerWithStatusBar.controller.statusBar.statusBarStyle
}
if self.currentStatusBarExternalHidden {
statusBarHidden = true
}
let resolvedStatusBarStyle: NavigationStatusBarStyle let resolvedStatusBarStyle: NavigationStatusBarStyle
switch statusBarStyle { switch statusBarStyle {
case .Ignore, .Hide: case .Ignore, .Hide:
@ -580,6 +706,11 @@ open class NavigationController: UINavigationController, ContainableController,
} }
self.statusBarHost?.setStatusBarStyle(normalStatusBarStyle, animated: animateStatusBarStyleTransition) self.statusBarHost?.setStatusBarStyle(normalStatusBarStyle, animated: animateStatusBarStyleTransition)
} }
if self.validStatusBarHidden != statusBarHidden {
self.validStatusBarHidden = statusBarHidden
self.statusBarHost?.setStatusBarHidden(statusBarHidden, animated: animateStatusBarStyleTransition)
}
} }
private func controllerRemoved(_ controller: ViewController) { private func controllerRemoved(_ controller: ViewController) {
@ -589,6 +720,28 @@ open class NavigationController: UINavigationController, ContainableController,
public func updateModalTransition(_ value: CGFloat, transition: ContainedViewLayoutTransition) { public func updateModalTransition(_ value: CGFloat, transition: ContainedViewLayoutTransition) {
} }
private func scrollToTop(_ subject: NavigationSplitContainerScrollToTop) {
if let _ = self.inCallStatusBar {
self.inCallNavigate?()
} else if let rootContainer = self.rootContainer {
if let modalContainer = self.modalContainers.last {
modalContainer.container.controllers.last?.scrollToTop?()
} else {
switch rootContainer {
case let .flat(container):
container.controllers.last?.scrollToTop?()
case let .split(container):
switch subject {
case .master:
container.masterControllers.last?.scrollToTop?()
case .detail:
container.detailControllers.last?.scrollToTop?()
}
}
}
}
}
public func updateToInterfaceOrientation(_ orientation: UIInterfaceOrientation) { public func updateToInterfaceOrientation(_ orientation: UIInterfaceOrientation) {
/*for record in self._viewControllers { /*for record in self._viewControllers {
if let controller = record.controller as? ContainableController { if let controller = record.controller as? ContainableController {
@ -613,9 +766,11 @@ open class NavigationController: UINavigationController, ContainableController,
} }
self.navigationBar.removeFromSuperview() self.navigationBar.removeFromSuperview()
/*let inCallStatusBar = StatusBar() let globalScrollToTopNode = ScrollToTopNode(action: { [weak self] in
self.displayNode.addSubnode(inCallStatusBar) self?.scrollToTop(.master)
self.inCallStatusBar = inCallStatusBar*/ })
self.displayNode.addSubnode(globalScrollToTopNode)
self.globalScrollToTopNode = globalScrollToTopNode
} }
public func pushViewController(_ controller: ViewController) { public func pushViewController(_ controller: ViewController) {
@ -750,6 +905,53 @@ open class NavigationController: UINavigationController, ContainableController,
} }
} }
public func presentOverlay(controller: ViewController, inGlobal: Bool = false) {
let container = NavigationOverlayContainer(controller: controller, controllerRemoved: { [weak self] controller in
guard let strongSelf = self else {
return
}
for i in 0 ..< strongSelf.overlayContainers.count {
let overlayContainer = strongSelf.overlayContainers[i]
if overlayContainer.controller === controller {
overlayContainer.removeFromSupernode()
strongSelf.overlayContainers.remove(at: i)
break
}
}
if let layout = strongSelf.validLayout {
strongSelf.updateContainers(layout: layout, transition: .immediate)
}
}, statusBarUpdated: { [weak self] transition in
guard let strongSelf = self else {
return
}
if let layout = strongSelf.validLayout {
strongSelf.updateContainers(layout: layout, transition: transition)
}
})
self.overlayContainers.append(container)
container.isReadyUpdated = { [weak self, weak container] in
guard let strongSelf = self, let container = container else {
return
}
if let layout = strongSelf.validLayout {
strongSelf.updateContainers(layout: layout, transition: .immediate)
}
}
if let layout = self.validLayout {
self.updateContainers(layout: layout, transition: .immediate)
}
}
func updateExternalStatusBarHidden(_ value: Bool, transition: ContainedViewLayoutTransition) {
if self.currentStatusBarExternalHidden != value {
self.currentStatusBarExternalHidden = value
if let layout = self.validLayout {
self.updateContainers(layout: layout, transition: transition)
}
}
}
override open func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) { override open func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
preconditionFailure() preconditionFailure()
} }
@ -816,4 +1018,49 @@ open class NavigationController: UINavigationController, ContainableController,
self.containerLayoutUpdated(validLayout, transition: transition) self.containerLayoutUpdated(validLayout, transition: transition)
} }
} }
public func setForceInCallStatusBar(_ forceInCallStatusBarText: String?, transition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .easeInOut)) {
if let forceInCallStatusBarText = forceInCallStatusBarText {
let inCallStatusBar: StatusBar
if let current = self.inCallStatusBar {
inCallStatusBar = current
} else {
inCallStatusBar = StatusBar()
inCallStatusBar.inCallNavigate = { [weak self] in
self?.scrollToTop(.master)
}
inCallStatusBar.alpha = 0.0
self.inCallStatusBar = inCallStatusBar
var bottomOverlayContainer: NavigationOverlayContainer?
for overlayContainer in self.overlayContainers {
if overlayContainer.supernode != nil {
bottomOverlayContainer = overlayContainer
break
}
}
if let bottomOverlayContainer = bottomOverlayContainer {
self.displayNode.insertSubnode(inCallStatusBar, belowSubnode: bottomOverlayContainer)
} else if let globalScrollToTopNode = self.globalScrollToTopNode {
self.displayNode.insertSubnode(inCallStatusBar, belowSubnode: globalScrollToTopNode)
} else {
self.displayNode.addSubnode(inCallStatusBar)
}
transition.updateAlpha(node: inCallStatusBar, alpha: 1.0)
}
if let layout = self.validLayout {
self.containerLayoutUpdated(layout, transition: transition)
inCallStatusBar.updateState(statusBar: nil, withSafeInsets: false, inCallText: forceInCallStatusBarText, animated: false)
}
} else if let inCallStatusBar = self.inCallStatusBar {
self.inCallStatusBar = nil
transition.updateAlpha(node: inCallStatusBar, alpha: 0.0, completion: { [weak inCallStatusBar] _ in
inCallStatusBar?.removeFromSupernode()
})
if let layout = self.validLayout {
self.containerLayoutUpdated(layout, transition: transition)
}
}
}
} }

View File

@ -33,6 +33,12 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes
} }
} }
var canHaveKeyboardFocus: Bool = false {
didSet {
self.container.canHaveKeyboardFocus = self.canHaveKeyboardFocus
}
}
init(theme: NavigationControllerTheme, controllerRemoved: @escaping (ViewController) -> Void) { init(theme: NavigationControllerTheme, controllerRemoved: @escaping (ViewController) -> Void) {
self.theme = theme self.theme = theme
@ -195,6 +201,8 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes
self.dismissProgress = dismissProgress self.dismissProgress = dismissProgress
self.applyDismissProgress(transition: transition, completion: {}) self.applyDismissProgress(transition: transition, completion: {})
self.view.endEditing(true)
} }
func scrollViewDidScroll(_ scrollView: UIScrollView) { func scrollViewDidScroll(_ scrollView: UIScrollView) {

View File

@ -0,0 +1,78 @@
import Foundation
import UIKit
import AsyncDisplayKit
import SwiftSignalKit
final class NavigationOverlayContainer: ASDisplayNode {
let controller: ViewController
private(set) var isReady: Bool = false
var isReadyUpdated: (() -> Void)?
private var isReadyDisposable: Disposable?
private var validLayout: ContainerViewLayout?
var keyboardViewManager: KeyboardViewManager? {
didSet {
if self.keyboardViewManager !== oldValue {
}
}
}
init(controller: ViewController, controllerRemoved: @escaping (ViewController) -> Void, statusBarUpdated: @escaping (ContainedViewLayoutTransition) -> Void) {
self.controller = controller
super.init()
self.controller.navigation_setDismiss({ [weak self] in
guard let strongSelf = self else {
return
}
controllerRemoved(strongSelf.controller)
}, rootController: nil)
self.controller.statusBar.alphaUpdated = { transition in
statusBarUpdated(transition)
}
self.isReadyDisposable = (self.controller.ready.get()
|> filter { $0 }
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] _ in
guard let strongSelf = self else {
return
}
if !strongSelf.isReady {
strongSelf.isReady = true
strongSelf.isReadyUpdated?()
}
})
}
deinit {
self.isReadyDisposable?.dispose()
}
override func didLoad() {
super.didLoad()
}
func update(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
let updateLayout = self.validLayout != layout
self.validLayout = layout
if updateLayout {
transition.updateFrame(node: self.controller.displayNode, frame: CGRect(origin: CGPoint(), size: layout.size))
self.controller.containerLayoutUpdated(layout, transition: transition)
}
}
func transitionIn() {
self.controller.viewWillAppear(false)
self.controller.setIgnoreAppearanceMethodInvocations(true)
self.addSubnode(self.controller.displayNode)
self.controller.setIgnoreAppearanceMethodInvocations(false)
self.controller.viewDidAppear(false)
}
}

View File

@ -3,19 +3,42 @@ import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import SwiftSignalKit import SwiftSignalKit
enum NavigationSplitContainerScrollToTop {
case master
case detail
}
final class NavigationSplitContainer: ASDisplayNode { final class NavigationSplitContainer: ASDisplayNode {
private var theme: NavigationControllerTheme private var theme: NavigationControllerTheme
private let masterScrollToTopView: ScrollToTopView
private let detailScrollToTopView: ScrollToTopView
private let masterContainer: NavigationContainer private let masterContainer: NavigationContainer
private let detailContainer: NavigationContainer private let detailContainer: NavigationContainer
private let separator: ASDisplayNode private let separator: ASDisplayNode
private var masterControllers: [ViewController] = [] private(set) var masterControllers: [ViewController] = []
private var detailControllers: [ViewController] = [] private(set) var detailControllers: [ViewController] = []
init(theme: NavigationControllerTheme, controllerRemoved: @escaping (ViewController) -> Void) { var canHaveKeyboardFocus: Bool = false {
didSet {
self.masterContainer.canHaveKeyboardFocus = self.canHaveKeyboardFocus
self.detailContainer.canHaveKeyboardFocus = self.canHaveKeyboardFocus
}
}
init(theme: NavigationControllerTheme, controllerRemoved: @escaping (ViewController) -> Void, scrollToTop: @escaping (NavigationSplitContainerScrollToTop) -> Void) {
self.theme = theme self.theme = theme
self.masterScrollToTopView = ScrollToTopView(frame: CGRect())
self.masterScrollToTopView.action = {
scrollToTop(.master)
}
self.detailScrollToTopView = ScrollToTopView(frame: CGRect())
self.detailScrollToTopView.action = {
scrollToTop(.detail)
}
self.masterContainer = NavigationContainer(controllerRemoved: controllerRemoved) self.masterContainer = NavigationContainer(controllerRemoved: controllerRemoved)
self.masterContainer.clipsToBounds = true self.masterContainer.clipsToBounds = true
@ -30,6 +53,8 @@ final class NavigationSplitContainer: ASDisplayNode {
self.addSubnode(self.masterContainer) self.addSubnode(self.masterContainer)
self.addSubnode(self.detailContainer) self.addSubnode(self.detailContainer)
self.addSubnode(self.separator) self.addSubnode(self.separator)
self.view.addSubview(self.masterScrollToTopView)
self.view.addSubview(self.detailScrollToTopView)
} }
func updateTheme(theme: NavigationControllerTheme) { func updateTheme(theme: NavigationControllerTheme) {
@ -40,6 +65,9 @@ final class NavigationSplitContainer: ASDisplayNode {
let masterWidth = min(max(320.0, floor(layout.size.width / 3.0)), floor(layout.size.width / 2.0)) let masterWidth = min(max(320.0, floor(layout.size.width / 3.0)), floor(layout.size.width / 2.0))
let detailWidth = layout.size.width - masterWidth let detailWidth = layout.size.width - masterWidth
self.masterScrollToTopView.frame = CGRect(origin: CGPoint(x: 0.0, y: -1.0), size: CGSize(width: masterWidth, height: 1.0))
self.detailScrollToTopView.frame = CGRect(origin: CGPoint(x: masterWidth, y: -1.0), size: CGSize(width: detailWidth, height: 1.0))
transition.updateFrame(node: self.masterContainer, frame: CGRect(origin: CGPoint(), size: CGSize(width: masterWidth, height: layout.size.height))) transition.updateFrame(node: self.masterContainer, frame: CGRect(origin: CGPoint(), size: CGSize(width: masterWidth, height: layout.size.height)))
transition.updateFrame(node: self.detailContainer, frame: CGRect(origin: CGPoint(x: masterWidth, y: 0.0), size: CGSize(width: detailWidth, height: layout.size.height))) transition.updateFrame(node: self.detailContainer, frame: CGRect(origin: CGPoint(x: masterWidth, y: 0.0), size: CGSize(width: detailWidth, height: layout.size.height)))
transition.updateFrame(node: self.separator, frame: CGRect(origin: CGPoint(x: masterWidth, y: 0.0), size: CGSize(width: UIScreenPixel, height: layout.size.height))) transition.updateFrame(node: self.separator, frame: CGRect(origin: CGPoint(x: masterWidth, y: 0.0), size: CGSize(width: UIScreenPixel, height: layout.size.height)))

View File

@ -35,3 +35,15 @@ class ScrollToTopView: UIScrollView, UIScrollViewDelegate {
return false return false
} }
} }
class ScrollToTopNode: ASDisplayNode {
init(action: @escaping () -> Void) {
super.init()
self.setViewBlock({
let view = ScrollToTopView(frame: CGRect())
view.action = action
return view
})
}
}

View File

@ -68,6 +68,7 @@ public final class StatusBar: ASDisplayNode {
didSet { didSet {
if self.statusBarStyle != oldValue { if self.statusBarStyle != oldValue {
self.layer.invalidateUpTheTree() self.layer.invalidateUpTheTree()
self.alphaUpdated?(.immediate)
} }
} }
} }
@ -94,6 +95,13 @@ public final class StatusBar: ASDisplayNode {
} }
} }
var alphaUpdated: ((ContainedViewLayoutTransition) -> Void)?
public func updateAlpha(_ alpha: CGFloat, transition: ContainedViewLayoutTransition) {
self.alpha = alpha
self.alphaUpdated?(transition)
}
public override init() { public override init() {
self.inCallLabel = StatusBarLabelNode() self.inCallLabel = StatusBarLabelNode()
self.inCallLabel.isUserInteractionEnabled = false self.inCallLabel.isUserInteractionEnabled = false

View File

@ -12,5 +12,8 @@ public protocol StatusBarHost {
var handleVolumeControl: Signal<Bool, NoError> { get } var handleVolumeControl: Signal<Bool, NoError> { get }
var isApplicationInForeground: Bool { get }
func setStatusBarStyle(_ style: UIStatusBarStyle, animated: Bool) func setStatusBarStyle(_ style: UIStatusBarStyle, animated: Bool)
func setStatusBarHidden(_ value: Bool, animated: Bool)
} }

View File

@ -127,6 +127,15 @@ open class TabBarController: ViewController {
self.theme = theme self.theme = theme
super.init(navigationBarPresentationData: navigationBarPresentationData) super.init(navigationBarPresentationData: navigationBarPresentationData)
self.scrollToTop = { [weak self] in
guard let strongSelf = self else {
return
}
if let controller = strongSelf.currentController {
controller.scrollToTop?()
}
}
} }
required public init(coder aDecoder: NSCoder) { required public init(coder aDecoder: NSCoder) {

View File

@ -246,7 +246,7 @@ public enum ViewControllerNavigationPresentation {
} }
private func updateScrollToTopView() { private func updateScrollToTopView() {
if self.scrollToTop != nil { /*if self.scrollToTop != nil {
if let displayNode = self._displayNode , self.scrollToTopView == nil { if let displayNode = self._displayNode , self.scrollToTopView == nil {
let scrollToTopView = ScrollToTopView(frame: CGRect(x: 0.0, y: -1.0, width: displayNode.bounds.size.width, height: 1.0)) let scrollToTopView = ScrollToTopView(frame: CGRect(x: 0.0, y: -1.0, width: displayNode.bounds.size.width, height: 1.0))
scrollToTopView.action = { [weak self] in scrollToTopView.action = { [weak self] in
@ -257,7 +257,7 @@ public enum ViewControllerNavigationPresentation {
self.scrollToTopView = scrollToTopView self.scrollToTopView = scrollToTopView
self.view.addSubview(scrollToTopView) self.view.addSubview(scrollToTopView)
} }
} else if let scrollToTopView = self.scrollToTopView { } else*/ if let scrollToTopView = self.scrollToTopView {
scrollToTopView.removeFromSuperview() scrollToTopView.removeFromSuperview()
self.scrollToTopView = nil self.scrollToTopView = nil
} }

View File

@ -280,7 +280,7 @@ public class Window1 {
private var deviceMetrics: DeviceMetrics private var deviceMetrics: DeviceMetrics
private let statusBarHost: StatusBarHost? private let statusBarHost: StatusBarHost?
private let statusBarManager: StatusBarManager? //private let statusBarManager: StatusBarManager?
private let keyboardManager: KeyboardManager? private let keyboardManager: KeyboardManager?
private let keyboardViewManager: KeyboardViewManager? private let keyboardViewManager: KeyboardViewManager?
private var statusBarChangeObserver: AnyObject? private var statusBarChangeObserver: AnyObject?
@ -312,7 +312,7 @@ public class Window1 {
public private(set) var forceInCallStatusBarText: String? = nil public private(set) var forceInCallStatusBarText: String? = nil
public var inCallNavigate: (() -> Void)? { public var inCallNavigate: (() -> Void)? {
didSet { didSet {
self.statusBarManager?.inCallNavigate = self.inCallNavigate //self.statusBarManager?.inCallNavigate = self.inCallNavigate
} }
} }
@ -323,21 +323,17 @@ public class Window1 {
private var keyboardTypeChangeTimer: SwiftSignalKit.Timer? private var keyboardTypeChangeTimer: SwiftSignalKit.Timer?
private let volumeControlStatusBar: VolumeControlStatusBar //private let volumeControlStatusBar: VolumeControlStatusBar
private let volumeControlStatusBarNode: VolumeControlStatusBarNode //private let volumeControlStatusBarNode: VolumeControlStatusBarNode
private var isInteractionBlocked = false private var isInteractionBlocked = false
/*private var accessibilityElements: [Any]? {
return self.viewController?.view.accessibilityElements
}*/
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)), shouldBeVisible: statusBarHost?.handleVolumeControl ?? .single(false)) //self.volumeControlStatusBar = VolumeControlStatusBar(frame: CGRect(origin: CGPoint(x: 0.0, y: -20.0), size: CGSize(width: 100.0, height: 20.0)), shouldBeVisible: statusBarHost?.handleVolumeControl ?? .single(false))
self.volumeControlStatusBarNode = VolumeControlStatusBarNode() //self.volumeControlStatusBarNode = VolumeControlStatusBarNode()
self.volumeControlStatusBarNode.isHidden = true //self.volumeControlStatusBarNode.isHidden = true
let boundsSize = self.hostView.eventView.bounds.size let boundsSize = self.hostView.eventView.bounds.size
self.deviceMetrics = DeviceMetrics(screenSize: UIScreen.main.bounds.size, statusBarHeight: statusBarHost?.statusBarFrame.height ?? defaultStatusBarHeight, onScreenNavigationHeight: self.hostView.onScreenNavigationHeight) self.deviceMetrics = DeviceMetrics(screenSize: UIScreen.main.bounds.size, statusBarHeight: statusBarHost?.statusBarFrame.height ?? defaultStatusBarHeight, onScreenNavigationHeight: self.hostView.onScreenNavigationHeight)
@ -346,12 +342,12 @@ public class Window1 {
let statusBarHeight: CGFloat let statusBarHeight: CGFloat
if let statusBarHost = statusBarHost { if let statusBarHost = statusBarHost {
statusBarHeight = statusBarHost.statusBarFrame.size.height statusBarHeight = statusBarHost.statusBarFrame.size.height
self.statusBarManager = StatusBarManager(host: statusBarHost, volumeControlStatusBar: self.volumeControlStatusBar, volumeControlStatusBarNode: self.volumeControlStatusBarNode) //self.statusBarManager = StatusBarManager(host: statusBarHost, volumeControlStatusBar: self.volumeControlStatusBar, volumeControlStatusBarNode: self.volumeControlStatusBarNode)
self.keyboardManager = KeyboardManager(host: statusBarHost) self.keyboardManager = KeyboardManager(host: statusBarHost)
self.keyboardViewManager = KeyboardViewManager(host: statusBarHost) self.keyboardViewManager = KeyboardViewManager(host: statusBarHost)
} else { } else {
statusBarHeight = self.deviceMetrics.statusBarHeight statusBarHeight = self.deviceMetrics.statusBarHeight
self.statusBarManager = nil //self.statusBarManager = nil
self.keyboardManager = nil self.keyboardManager = nil
self.keyboardViewManager = nil self.keyboardViewManager = nil
} }
@ -394,7 +390,7 @@ public class Window1 {
} }
self.hostView.layoutSubviews = { [weak self] in self.hostView.layoutSubviews = { [weak self] in
self?.layoutSubviews() self?.layoutSubviews(force: false)
} }
self.hostView.updateToInterfaceOrientation = { [weak self] orientation in self.hostView.updateToInterfaceOrientation = { [weak self] orientation in
@ -433,7 +429,7 @@ public class Window1 {
}*/ }*/
self.presentationContext.view = self.hostView.containerView self.presentationContext.view = self.hostView.containerView
self.presentationContext.volumeControlStatusBarNodeView = self.volumeControlStatusBarNode.view //self.presentationContext.volumeControlStatusBarNodeView = self.volumeControlStatusBarNode.view
self.presentationContext.containerLayoutUpdated(containedLayoutForWindowLayout(self.windowLayout, deviceMetrics: self.deviceMetrics), transition: .immediate) self.presentationContext.containerLayoutUpdated(containedLayoutForWindowLayout(self.windowLayout, deviceMetrics: self.deviceMetrics), transition: .immediate)
self.overlayPresentationContext.containerLayoutUpdated(containedLayoutForWindowLayout(self.windowLayout, deviceMetrics: self.deviceMetrics), transition: .immediate) self.overlayPresentationContext.containerLayoutUpdated(containedLayoutForWindowLayout(self.windowLayout, deviceMetrics: self.deviceMetrics), transition: .immediate)
@ -455,7 +451,7 @@ public class Window1 {
keyboardHeight = max(0.0, keyboardHeight - 24.0) keyboardHeight = max(0.0, keyboardHeight - 24.0)
} }
print("keyboardHeight: \(keyboardHeight)") //print("rotation keyboardHeight: \(keyboardHeight)")
var duration: Double = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0.0 var duration: Double = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0.0
if duration > Double.ulpOfOne { if duration > Double.ulpOfOne {
@ -483,12 +479,31 @@ public class Window1 {
} }
} }
var popoverDelta: CGFloat = 0.0
let screenHeight: CGFloat let screenHeight: CGFloat
var inPopover = false var inPopover = false
if keyboardFrame.width.isEqual(to: UIScreen.main.bounds.width) { if keyboardFrame.width.isEqual(to: UIScreen.main.bounds.width) {
var portraitScreenSize = UIScreen.main.bounds.size
if portraitScreenSize.width > portraitScreenSize.height {
portraitScreenSize = CGSize(width: portraitScreenSize.height, height: portraitScreenSize.width)
}
var portraitLayoutSize = strongSelf.windowLayout.size
if portraitLayoutSize.width > portraitLayoutSize.height {
portraitLayoutSize = CGSize(width: portraitLayoutSize.height, height: portraitLayoutSize.width)
}
if abs(strongSelf.windowLayout.size.height - UIScreen.main.bounds.height) > 41.0 { if abs(strongSelf.windowLayout.size.height - UIScreen.main.bounds.height) > 41.0 {
screenHeight = UIScreen.main.bounds.height screenHeight = UIScreen.main.bounds.height
inPopover = true if abs(portraitLayoutSize.height - portraitScreenSize.height) > 41.0 || abs(portraitLayoutSize.width - portraitScreenSize.width) > 41.0 {
popoverDelta = 48.0
inPopover = true
}
} else if abs(strongSelf.windowLayout.size.height - UIScreen.main.bounds.height) > 39.0 {
screenHeight = UIScreen.main.bounds.height
if abs(portraitLayoutSize.height - portraitScreenSize.height) > 39.0 || abs(portraitLayoutSize.width - portraitScreenSize.width) > 39.0 {
popoverDelta = 40.0
inPopover = true
}
} else { } else {
screenHeight = strongSelf.windowLayout.size.height screenHeight = strongSelf.windowLayout.size.height
} }
@ -503,14 +518,14 @@ public class Window1 {
keyboardHeight = max(0.0, screenHeight - keyboardFrame.minY) keyboardHeight = max(0.0, screenHeight - keyboardFrame.minY)
if inPopover { if inPopover {
if strongSelf.windowLayout.onScreenNavigationHeight != nil { if strongSelf.windowLayout.onScreenNavigationHeight != nil {
keyboardHeight = max(0.0, keyboardHeight - 24.0) keyboardHeight = max(0.0, keyboardHeight - popoverDelta / 2.0)
} else { } else {
keyboardHeight = max(0.0, keyboardHeight - 48.0) keyboardHeight = max(0.0, keyboardHeight - popoverDelta)
} }
} }
} }
print("keyboardHeight: \(keyboardHeight)") print("keyboardHeight: \(keyboardHeight) (raw: \(keyboardFrame))")
var duration: Double = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0.0 var duration: Double = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0.0
if duration > Double.ulpOfOne { if duration > Double.ulpOfOne {
@ -586,8 +601,8 @@ public class Window1 {
self.windowPanRecognizer = recognizer self.windowPanRecognizer = recognizer
self.hostView.containerView.addGestureRecognizer(recognizer) self.hostView.containerView.addGestureRecognizer(recognizer)
self.hostView.containerView.addSubview(self.volumeControlStatusBar) //self.hostView.containerView.addSubview(self.volumeControlStatusBar)
self.hostView.containerView.addSubview(self.volumeControlStatusBarNode.view) //self.hostView.containerView.addSubview(self.volumeControlStatusBarNode.view)
} }
public required init(coder aDecoder: NSCoder) { public required init(coder aDecoder: NSCoder) {
@ -613,7 +628,7 @@ public class Window1 {
} }
public func setupVolumeControlStatusBarGraphics(_ graphics: (UIImage, UIImage, UIImage)) { public func setupVolumeControlStatusBarGraphics(_ graphics: (UIImage, UIImage, UIImage)) {
self.volumeControlStatusBarNode.graphics = graphics //self.volumeControlStatusBarNode.graphics = graphics
} }
public func setForceInCallStatusBar(_ forceInCallStatusBarText: String?, transition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .easeInOut)) { public func setForceInCallStatusBar(_ forceInCallStatusBarText: String?, transition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .easeInOut)) {
@ -701,6 +716,9 @@ public class Window1 {
transition = .immediate transition = .immediate
} }
self.updateLayout { $0.update(size: value, metrics: layoutMetricsForScreenSize(value), safeInsets: self.deviceMetrics.safeInsets(inLandscape: value.width > value.height), forceInCallStatusBarText: self.forceInCallStatusBarText, transition: transition, overrideTransition: true) } self.updateLayout { $0.update(size: value, metrics: layoutMetricsForScreenSize(value), safeInsets: self.deviceMetrics.safeInsets(inLandscape: value.width > value.height), forceInCallStatusBarText: self.forceInCallStatusBarText, transition: transition, overrideTransition: true) }
if let statusBarHost = self.statusBarHost, !statusBarHost.isApplicationInForeground {
self.layoutSubviews(force: true)
}
} }
private var _rootController: ContainableController? private var _rootController: ContainableController?
@ -718,6 +736,9 @@ public class Window1 {
if let rootController = rootController as? NavigationController { if let rootController = rootController as? NavigationController {
rootController.statusBarHost = self.statusBarHost rootController.statusBarHost = self.statusBarHost
rootController.keyboardViewManager = self.keyboardViewManager rootController.keyboardViewManager = self.keyboardViewManager
rootController.inCallNavigate = { [weak self] in
self?.inCallNavigate?()
}
} }
if !self.windowLayout.size.width.isZero && !self.windowLayout.size.height.isZero { if !self.windowLayout.size.width.isZero && !self.windowLayout.size.height.isZero {
rootController.displayNode.frame = CGRect(origin: CGPoint(), size: self.windowLayout.size) rootController.displayNode.frame = CGRect(origin: CGPoint(), size: self.windowLayout.size)
@ -738,6 +759,9 @@ public class Window1 {
} }
set(value) { set(value) {
for controller in self._topLevelOverlayControllers { for controller in self._topLevelOverlayControllers {
if let controller = controller as? ViewController {
controller.statusBar.alphaUpdated = nil
}
controller.view.removeFromSuperview() controller.view.removeFromSuperview()
} }
self._topLevelOverlayControllers = value self._topLevelOverlayControllers = value
@ -750,7 +774,25 @@ public class Window1 {
if let coveringView = self.coveringView { if let coveringView = self.coveringView {
self.hostView.containerView.insertSubview(controller.view, belowSubview: coveringView) self.hostView.containerView.insertSubview(controller.view, belowSubview: coveringView)
} else { } else {
self.hostView.containerView.insertSubview(controller.view, belowSubview: self.volumeControlStatusBarNode.view) self.hostView.containerView.addSubview(controller.view)
}
if let controller = controller as? ViewController {
controller.statusBar.alphaUpdated = { [weak self] transition in
guard let strongSelf = self, let navigationController = strongSelf._rootController as? NavigationController else {
return
}
var isStatusBarHidden: Bool = false
for controller in strongSelf._topLevelOverlayControllers {
if let controller = controller as? ViewController {
if case .Hide = controller.statusBar.statusBarStyle {
isStatusBarHidden = true
}
}
}
navigationController.updateExternalStatusBarHidden(isStatusBarHidden, transition: .animated(duration: 0.3, curve: .easeInOut))
}
} }
} }
@ -771,7 +813,7 @@ public class Window1 {
coveringView.layer.removeAnimation(forKey: "opacity") coveringView.layer.removeAnimation(forKey: "opacity")
coveringView.layer.allowsGroupOpacity = false coveringView.layer.allowsGroupOpacity = false
coveringView.alpha = 1.0 coveringView.alpha = 1.0
self.hostView.containerView.insertSubview(coveringView, belowSubview: self.volumeControlStatusBarNode.view) self.hostView.containerView.addSubview(coveringView)
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)
@ -781,7 +823,7 @@ public class Window1 {
} }
} }
private func layoutSubviews() { private func layoutSubviews(force: Bool) {
var hasPreview = false var hasPreview = false
var updatedHasPreview = false var updatedHasPreview = false
for subview in self.hostView.eventView.subviews { for subview in self.hostView.eventView.subviews {
@ -796,7 +838,7 @@ public class Window1 {
updatedHasPreview = true updatedHasPreview = true
} }
if self.tracingStatusBarsInvalidated || updatedHasPreview, let statusBarManager = statusBarManager, let keyboardManager = keyboardManager { if self.tracingStatusBarsInvalidated || updatedHasPreview, let keyboardManager = keyboardManager {
self.tracingStatusBarsInvalidated = false self.tracingStatusBarsInvalidated = false
/*if self.statusBarHidden { /*if self.statusBarHidden {
@ -902,7 +944,9 @@ public class Window1 {
} }
} }
if !UIWindow.isDeviceRotating() { if force {
self.commitUpdatingLayout()
} else if !UIWindow.isDeviceRotating() {
if !self.hostView.isUpdatingOrientationLayout { if !self.hostView.isUpdatingOrientationLayout {
self.commitUpdatingLayout() self.commitUpdatingLayout()
} else { } else {
@ -967,6 +1011,9 @@ public class Window1 {
let boundsSize = updatingLayout.layout.size let boundsSize = updatingLayout.layout.size
let isLandscape = boundsSize.width > boundsSize.height let isLandscape = boundsSize.width > boundsSize.height
var statusBarHeight: CGFloat? = self.deviceMetrics.statusBarHeight(for: boundsSize) var statusBarHeight: CGFloat? = self.deviceMetrics.statusBarHeight(for: boundsSize)
if let statusBarHeightValue = statusBarHeight, let statusBarHost = self.statusBarHost {
statusBarHeight = max(statusBarHeightValue, statusBarHost.statusBarFrame.size.height)
}
if self.deviceMetrics.type == .tablet, let onScreenNavigationHeight = self.hostView.onScreenNavigationHeight, onScreenNavigationHeight != self.deviceMetrics.onScreenNavigationHeight(inLandscape: false) { if self.deviceMetrics.type == .tablet, let onScreenNavigationHeight = self.hostView.onScreenNavigationHeight, onScreenNavigationHeight != self.deviceMetrics.onScreenNavigationHeight(inLandscape: false) {
self.deviceMetrics = DeviceMetrics(screenSize: UIScreen.main.bounds.size, statusBarHeight: statusBarHeight ?? defaultStatusBarHeight, onScreenNavigationHeight: onScreenNavigationHeight) self.deviceMetrics = DeviceMetrics(screenSize: UIScreen.main.bounds.size, statusBarHeight: statusBarHeight ?? defaultStatusBarHeight, onScreenNavigationHeight: onScreenNavigationHeight)
@ -1023,8 +1070,8 @@ public class Window1 {
}) })
} }
self.volumeControlStatusBarNode.frame = CGRect(origin: CGPoint(), size: self.windowLayout.size) //self.volumeControlStatusBarNode.frame = CGRect(origin: CGPoint(), size: self.windowLayout.size)
self.volumeControlStatusBarNode.updateLayout(layout: childLayout, transition: updatingLayout.transition) //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)
@ -1035,7 +1082,12 @@ public class Window1 {
} }
public func present(_ controller: ContainableController, on level: PresentationSurfaceLevel, blockInteraction: Bool = false, completion: @escaping () -> Void = {}) { public func present(_ controller: ContainableController, on level: PresentationSurfaceLevel, blockInteraction: Bool = false, completion: @escaping () -> Void = {}) {
self.presentationContext.present(controller, on: level, blockInteraction: blockInteraction, completion: completion) if let navigationController = self._rootController as? NavigationController, let controller = controller as? ViewController {
navigationController.presentOverlay(controller: controller, inGlobal: false)
} else {
assertionFailure()
}
//self.presentationContext.present(controller, on: level, blockInteraction: blockInteraction, completion: completion)
} }
public func presentInGlobalOverlay(_ controller: ContainableController) { public func presentInGlobalOverlay(_ controller: ContainableController) {

View File

@ -275,14 +275,14 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture
UIView.animate(withDuration: 0.3, animations: { UIView.animate(withDuration: 0.3, animations: {
let alpha: CGFloat = self.areControlsHidden ? 0.0 : 1.0 let alpha: CGFloat = self.areControlsHidden ? 0.0 : 1.0
self.navigationBar?.alpha = alpha self.navigationBar?.alpha = alpha
self.statusBar?.alpha = alpha self.statusBar?.updateAlpha(alpha, transition: .animated(duration: 0.3, curve: .easeInOut))
self.footerNode.alpha = alpha self.footerNode.alpha = alpha
self.updateThumbnailContainerNodeAlpha(.immediate) self.updateThumbnailContainerNodeAlpha(.immediate)
}) })
} else { } else {
let alpha: CGFloat = self.areControlsHidden ? 0.0 : 1.0 let alpha: CGFloat = self.areControlsHidden ? 0.0 : 1.0
self.navigationBar?.alpha = alpha self.navigationBar?.alpha = alpha
self.statusBar?.alpha = alpha self.statusBar?.updateAlpha(alpha, transition: .immediate)
self.footerNode.alpha = alpha self.footerNode.alpha = alpha
self.updateThumbnailContainerNodeAlpha(.immediate) self.updateThumbnailContainerNodeAlpha(.immediate)
} }
@ -374,7 +374,11 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture
self.updateThumbnailContainerNodeAlpha(.immediate) self.updateThumbnailContainerNodeAlpha(.immediate)
if !self.areControlsHidden { if !self.areControlsHidden {
self.statusBar?.alpha = transition if transition < 0.5 {
self.statusBar?.updateAlpha(0.0, transition: .animated(duration: 0.3, curve: .easeInOut))
} else {
self.statusBar?.updateAlpha(1.0, transition: .animated(duration: 0.3, curve: .easeInOut))
}
self.navigationBar?.alpha = transition self.navigationBar?.alpha = transition
self.footerNode.alpha = transition self.footerNode.alpha = transition

View File

@ -364,10 +364,10 @@ open class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UISc
addedInsets = UIEdgeInsets(top: 0.0, left: inset, bottom: 0.0, right: inset) addedInsets = UIEdgeInsets(top: 0.0, left: inset, bottom: 0.0, right: inset)
if self.leftOverlayNode.supernode == nil { if self.leftOverlayNode.supernode == nil {
self.addSubnode(self.leftOverlayNode) self.insertSubnode(self.leftOverlayNode, aboveSubnode: self.listNode)
} }
if self.rightOverlayNode.supernode == nil { if self.rightOverlayNode.supernode == nil {
self.addSubnode(self.rightOverlayNode) self.insertSubnode(self.rightOverlayNode, aboveSubnode: self.listNode)
} }
} else { } else {
insets.left += layout.safeInsets.left insets.left += layout.safeInsets.left

View File

@ -93,13 +93,15 @@
- (BOOL)prefersStatusBarHidden - (BOOL)prefersStatusBarHidden
{ {
if (!TGIsPad() && iosMajorVersion() >= 11 && UIInterfaceOrientationIsLandscape([[LegacyComponentsGlobals provider] applicationStatusBarOrientation])) return true;
/*if (!TGIsPad() && iosMajorVersion() >= 11 && UIInterfaceOrientationIsLandscape([[LegacyComponentsGlobals provider] applicationStatusBarOrientation]))
return true; return true;
if (self.childViewControllers.count > 0) if (self.childViewControllers.count > 0)
return [self.childViewControllers.lastObject prefersStatusBarHidden]; return [self.childViewControllers.lastObject prefersStatusBarHidden];
return [super prefersStatusBarHidden]; return [super prefersStatusBarHidden];*/
} }
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures - (UIRectEdge)preferredScreenEdgesDeferringSystemGestures
@ -262,7 +264,7 @@
{ {
[UIView animateWithDuration:0.2 animations:^ [UIView animateWithDuration:0.2 animations:^
{ {
[strongSelf->_context setApplicationStatusBarAlpha:1.0f]; //[strongSelf->_context setApplicationStatusBarAlpha:1.0f];
}]; }];
} }
@ -1155,7 +1157,7 @@ static CGFloat transformRotation(CGAffineTransform transform)
{ {
[UIView animateWithDuration:0.2 animations:^ [UIView animateWithDuration:0.2 animations:^
{ {
[_context setApplicationStatusBarAlpha:1.0f]; //[_context setApplicationStatusBarAlpha:1.0f];
}]; }];
} }
} }
@ -1228,7 +1230,7 @@ static CGFloat transformRotation(CGAffineTransform transform)
if (self.adjustsStatusBarVisibility) if (self.adjustsStatusBarVisibility)
{ {
[_context setApplicationStatusBarAlpha:1.0f]; //[_context setApplicationStatusBarAlpha:1.0f];
} }
} }

View File

@ -247,7 +247,7 @@ public final class LegacyControllerContext: NSObject, LegacyComponentsContext {
public func setApplicationStatusBarAlpha(_ alpha: CGFloat) { public func setApplicationStatusBarAlpha(_ alpha: CGFloat) {
if let controller = self.controller { if let controller = self.controller {
controller.statusBar.alpha = alpha controller.statusBar.updateAlpha(alpha, transition: .immediate)
self.updateDeferScreenEdgeGestures() self.updateDeferScreenEdgeGestures()
} }
} }

View File

@ -21,6 +21,8 @@ public extension Peer {
} }
} else if let lastName = user.lastName { } else if let lastName = user.lastName {
return lastName return lastName
} else if let phone = user.phone {
return "+\(phone)"
} else { } else {
return strings.User_DeletedAccount return strings.User_DeletedAccount
} }

View File

@ -29,6 +29,8 @@
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Debug"
@ -40,6 +42,17 @@
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES"
debugServiceExtension = "internal" debugServiceExtension = "internal"
allowLocationSimulation = "YES"> allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E66DC04E89A74F8D00000000"
BuildableName = "libSwiftSignalKit.dylib"
BlueprintName = "SwiftSignalKit#shared"
ReferencedContainer = "container:SwiftSignalKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release" buildConfiguration = "Release"

View File

@ -1102,9 +1102,13 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|> mapToSignal { context in |> mapToSignal { context in
return context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) return context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration])
|> map { view -> Bool in |> map { view -> Bool in
let appConfiguration = view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue if #available(iOSApplicationExtension 10.3, iOS 10.3, *) {
let configuration = WalletConfiguration.with(appConfiguration: appConfiguration) let appConfiguration = view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue
return configuration.config != nil let configuration = WalletConfiguration.with(appConfiguration: appConfiguration)
return configuration.config != nil
} else {
return false
}
} }
} }
@ -1375,7 +1379,7 @@ public func settingsController(context: AccountContext, accountManager: AccountM
(controller?.navigationController as? NavigationController)?.replaceAllButRootController(value, animated: true, animationOptions: [.removeOnMasterDetails]) (controller?.navigationController as? NavigationController)?.replaceAllButRootController(value, animated: true, animationOptions: [.removeOnMasterDetails])
} }
presentControllerImpl = { [weak controller] value, arguments in presentControllerImpl = { [weak controller] value, arguments in
controller?.present(value, in: .window(.root), with: arguments ?? ViewControllerPresentationArguments(presentationAnimation: .modalSheet), blockInteraction: true) controller?.present(value, in: .window(.root), with: arguments, blockInteraction: true)
} }
presentInGlobalOverlayImpl = { [weak controller] value, arguments in presentInGlobalOverlayImpl = { [weak controller] value, arguments in
controller?.presentInGlobalOverlay(value, with: arguments) controller?.presentInGlobalOverlay(value, with: arguments)

View File

@ -54,7 +54,7 @@ public extension TermsOfServiceControllerTheme {
} }
} }
public class TermsOfServiceController: ViewController { public class TermsOfServiceController: ViewController, StandalonePresentableController {
private var controllerNode: TermsOfServiceControllerNode { private var controllerNode: TermsOfServiceControllerNode {
return self.displayNode as! TermsOfServiceControllerNode return self.displayNode as! TermsOfServiceControllerNode
} }

View File

@ -271,6 +271,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
override func didLoad() { override func didLoad() {
super.didLoad() super.didLoad()
self.scrollNode.view.disablesInteractiveTransitionGestureRecognizer = true
self.scrollNode.view.showsHorizontalScrollIndicator = false self.scrollNode.view.showsHorizontalScrollIndicator = false
self.scrollNode.view.isPagingEnabled = true self.scrollNode.view.isPagingEnabled = true
self.scrollNode.view.delegate = self self.scrollNode.view.delegate = self

View File

@ -129,7 +129,7 @@ public extension Peer {
var isDeleted: Bool { var isDeleted: Bool {
switch self { switch self {
case let user as TelegramUser: case let user as TelegramUser:
return user.firstName == nil && user.lastName == nil return user.firstName == nil && user.lastName == nil && user.phone == nil
default: default:
return false return false
} }

View File

@ -28,6 +28,7 @@ public enum TonKeychainEncryptDataError {
public enum TonKeychainDecryptDataError { public enum TonKeychainDecryptDataError {
case generic case generic
case publicKeyMismatch case publicKeyMismatch
case cancelled
} }
public struct TonKeychain { public struct TonKeychain {
@ -332,8 +333,8 @@ public final class TonInstance {
fileprivate func walletRestoreWords(walletInfo: WalletInfo, keychain: TonKeychain, serverSalt: Data) -> Signal<[String], WalletRestoreWordsError> { fileprivate func walletRestoreWords(walletInfo: WalletInfo, keychain: TonKeychain, serverSalt: Data) -> Signal<[String], WalletRestoreWordsError> {
return keychain.decrypt(walletInfo.encryptedSecret) return keychain.decrypt(walletInfo.encryptedSecret)
|> mapError { _ -> WalletRestoreWordsError in |> mapError { error -> WalletRestoreWordsError in
return .secretDecryptionFailed return .secretDecryptionFailed(error)
} }
|> mapToSignal { decryptedSecret -> Signal<[String], WalletRestoreWordsError> in |> mapToSignal { decryptedSecret -> Signal<[String], WalletRestoreWordsError> in
return Signal { subscriber in return Signal { subscriber in
@ -365,8 +366,8 @@ public final class TonInstance {
fileprivate func deleteLocalWalletData(walletInfo: WalletInfo, keychain: TonKeychain, serverSalt: Data) -> Signal<Never, DeleteLocalWalletDataError> { fileprivate func deleteLocalWalletData(walletInfo: WalletInfo, keychain: TonKeychain, serverSalt: Data) -> Signal<Never, DeleteLocalWalletDataError> {
return keychain.decrypt(walletInfo.encryptedSecret) return keychain.decrypt(walletInfo.encryptedSecret)
|> mapError { _ -> DeleteLocalWalletDataError in |> mapError { error -> DeleteLocalWalletDataError in
return .secretDecryptionFailed return .secretDecryptionFailed(error)
} }
|> mapToSignal { decryptedSecret -> Signal<Never, DeleteLocalWalletDataError> in |> mapToSignal { decryptedSecret -> Signal<Never, DeleteLocalWalletDataError> in
return Signal { subscriber in return Signal { subscriber in
@ -581,7 +582,7 @@ public func importWallet(postbox: Postbox, network: Network, tonInstance: TonIns
public enum DeleteLocalWalletDataError { public enum DeleteLocalWalletDataError {
case generic case generic
case secretDecryptionFailed case secretDecryptionFailed(TonKeychainDecryptDataError)
} }
public func deleteLocalWalletData(postbox: Postbox, network: Network, tonInstance: TonInstance, keychain: TonKeychain, walletInfo: WalletInfo) -> Signal<Never, DeleteLocalWalletDataError> { public func deleteLocalWalletData(postbox: Postbox, network: Network, tonInstance: TonInstance, keychain: TonKeychain, walletInfo: WalletInfo) -> Signal<Never, DeleteLocalWalletDataError> {
@ -612,7 +613,7 @@ public func deleteLocalWalletData(postbox: Postbox, network: Network, tonInstanc
public enum WalletRestoreWordsError { public enum WalletRestoreWordsError {
case generic case generic
case secretDecryptionFailed case secretDecryptionFailed(TonKeychainDecryptDataError)
} }
public func walletRestoreWords(network: Network, walletInfo: WalletInfo, tonInstance: TonInstance, keychain: TonKeychain) -> Signal<[String], WalletRestoreWordsError> { public func walletRestoreWords(network: Network, walletInfo: WalletInfo, tonInstance: TonInstance, keychain: TonKeychain) -> Signal<[String], WalletRestoreWordsError> {

View File

@ -56,6 +56,15 @@ private let keyboardWindowClass: AnyClass? = {
private class ApplicationStatusBarHost: StatusBarHost { private class ApplicationStatusBarHost: StatusBarHost {
private let application = UIApplication.shared private let application = UIApplication.shared
var isApplicationInForeground: Bool {
switch self.application.applicationState {
case .background:
return false
default:
return true
}
}
var statusBarFrame: CGRect { var statusBarFrame: CGRect {
return self.application.statusBarFrame return self.application.statusBarFrame
} }
@ -71,6 +80,10 @@ private class ApplicationStatusBarHost: StatusBarHost {
self.application.setStatusBarStyle(style, animated: animated) self.application.setStatusBarStyle(style, animated: animated)
} }
func setStatusBarHidden(_ value: Bool, animated: Bool) {
self.application.setStatusBarHidden(value, with: animated ? .fade : .none)
}
var statusBarWindow: UIView? { var statusBarWindow: UIView? {
return self.application.value(forKey: "statusBarWindow") as? UIView return self.application.value(forKey: "statusBarWindow") as? UIView
} }
@ -664,6 +677,7 @@ final class SharedApplicationContext {
#if targetEnvironment(simulator) #if targetEnvironment(simulator)
tonKeychain = TonKeychain(encryptionPublicKey: { tonKeychain = TonKeychain(encryptionPublicKey: {
//return .single(nil) //return .single(nil)
//return .single("1".data(using: .utf8)!)
return .single(Data()) return .single(Data())
}, encrypt: { data in }, encrypt: { data in
return Signal { subscriber in return Signal { subscriber in
@ -701,11 +715,17 @@ final class SharedApplicationContext {
} }
}, decrypt: { encryptedData in }, decrypt: { encryptedData in
return Signal { subscriber in return Signal { subscriber in
BuildConfig.decryptApplicationSecret(encryptedData.data, publicKey: encryptedData.publicKey, baseAppBundleId: baseAppBundleId, completion: { result in BuildConfig.decryptApplicationSecret(encryptedData.data, publicKey: encryptedData.publicKey, baseAppBundleId: baseAppBundleId, completion: { result, cancelled in
if let result = result { if let result = result {
subscriber.putNext(result) subscriber.putNext(result)
} else { } else {
subscriber.putError(.generic) let error: TonKeychainDecryptDataError
if cancelled {
error = .cancelled
} else {
error = .generic
}
subscriber.putError(error)
} }
subscriber.putCompletion() subscriber.putCompletion()
}) })
@ -1259,9 +1279,12 @@ final class SharedApplicationContext {
#endif #endif
} }
if UIApplication.shared.isStatusBarHidden {
UIApplication.shared.setStatusBarHidden(false, with: .none)
}
NotificationCenter.default.addObserver(forName: UIWindow.didBecomeHiddenNotification, object: nil, queue: nil, using: { notification in NotificationCenter.default.addObserver(forName: UIWindow.didBecomeHiddenNotification, object: nil, queue: nil, using: { notification in
if UIApplication.shared.isStatusBarHidden { if UIApplication.shared.isStatusBarHidden {
UIApplication.shared.setStatusBarHidden(false, with: .none) //UIApplication.shared.setStatusBarHidden(false, with: .none)
} }
}) })
return true return true

View File

@ -456,6 +456,7 @@ final class AuthorizedApplicationContext {
}, expandAction: { expandData in }, expandAction: { expandData in
if let strongSelf = self { if let strongSelf = self {
let chatController = ChatControllerImpl(context: strongSelf.context, chatLocation: .peer(firstMessage.id.peerId), mode: .overlay) let chatController = ChatControllerImpl(context: strongSelf.context, chatLocation: .peer(firstMessage.id.peerId), mode: .overlay)
//chatController.navigation_setNavigationController(strongSelf.rootController)
(strongSelf.rootController.viewControllers.last as? ViewController)?.present(chatController, in: .window(.root), with: ChatControllerOverlayPresentationData(expandData: expandData())) (strongSelf.rootController.viewControllers.last as? ViewController)?.present(chatController, in: .window(.root), with: ChatControllerOverlayPresentationData(expandData: expandData()))
} }
})) }))

View File

@ -2312,7 +2312,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
private func themeAndStringsUpdated() { private func themeAndStringsUpdated() {
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil) self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style switch self.presentationInterfaceState.mode {
case .standard:
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
self.deferScreenEdgeGestures = []
case .overlay:
self.statusBar.statusBarStyle = .Hide
self.deferScreenEdgeGestures = [.top]
case .inline:
self.statusBar.statusBarStyle = .Ignore
}
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData)) self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData))
self.chatTitleView?.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings) self.chatTitleView?.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings)
self.updateChatPresentationInterfaceState(animated: false, interactive: false, { state in self.updateChatPresentationInterfaceState(animated: false, interactive: false, { state in
@ -2589,22 +2598,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.chatDisplayNode.historyNode.contentPositionChanged = { [weak self] offset in self.chatDisplayNode.historyNode.contentPositionChanged = { [weak self] offset in
if let strongSelf = self { if let strongSelf = self {
let offsetAlpha: CGFloat let offsetAlpha: CGFloat
if case let .standard(previewing) = strongSelf.presentationInterfaceState.mode, previewing { switch offset {
offsetAlpha = 0.0 case let .known(offset):
} else { if offset < 40.0 {
switch offset {
case let .known(offset):
if offset < 40.0 {
offsetAlpha = 0.0
} else {
offsetAlpha = 1.0
}
case .unknown:
offsetAlpha = 1.0
case .none:
offsetAlpha = 0.0 offsetAlpha = 0.0
} } else {
offsetAlpha = 1.0
}
case .unknown:
offsetAlpha = 1.0
case .none:
offsetAlpha = 0.0
} }
strongSelf.chatDisplayNode.navigateButtons.displayDownButton = !offsetAlpha.isZero strongSelf.chatDisplayNode.navigateButtons.displayDownButton = !offsetAlpha.isZero
} }
} }

View File

@ -1903,6 +1903,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
switch self.chatPresentationInterfaceState.mode { switch self.chatPresentationInterfaceState.mode {
case .standard(previewing: true): case .standard(previewing: true):
if let result = self.navigateButtons.hitTest(self.view.convert(point, to: self.navigateButtons.view), with: event) {
return result
}
if self.bounds.contains(point) { if self.bounds.contains(point) {
return self.historyNode.view return self.historyNode.view
} }

View File

@ -15,6 +15,8 @@ public final class NotificationContainerController: ViewController {
private var presentationData: PresentationData private var presentationData: PresentationData
private var presentationDataDisposable: Disposable? private var presentationDataDisposable: Disposable?
private var validLayout: ContainerViewLayout?
public init(context: AccountContext) { public init(context: AccountContext) {
self.presentationData = context.sharedContext.currentPresentationData.with { $0 } self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
@ -61,7 +63,15 @@ public final class NotificationContainerController: ViewController {
self.controllerNode.displayingItemsUpdated = { [weak self] value in self.controllerNode.displayingItemsUpdated = { [weak self] value in
if let strongSelf = self { if let strongSelf = self {
strongSelf.statusBar.statusBarStyle = value ? .Hide : .Ignore var statusBarHidden = false
if value, let layout = strongSelf.validLayout {
if let statusBarHeight = layout.statusBarHeight, statusBarHeight > 20.0 {
statusBarHidden = false
} else {
statusBarHidden = true
}
}
strongSelf.statusBar.statusBarStyle = statusBarHidden ? .Hide : .Ignore
if value { if value {
strongSelf.deferScreenEdgeGestures = [.top] strongSelf.deferScreenEdgeGestures = [.top]
} else { } else {
@ -72,6 +82,8 @@ public final class NotificationContainerController: ViewController {
} }
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
self.validLayout = layout
super.containerLayoutUpdated(layout, transition: transition) super.containerLayoutUpdated(layout, transition: transition)
self.controllerNode.containerLayoutUpdated(layout, transition: transition) self.controllerNode.containerLayoutUpdated(layout, transition: transition)

View File

@ -68,29 +68,19 @@ final class NotificationContainerControllerNode: ASDisplayNode {
if let (item, topItemNode) = self.topItemAndNode { if let (item, topItemNode) = self.topItemAndNode {
if item.groupingKey == key { if item.groupingKey == key {
self.topItemAndNode = nil self.topItemAndNode = nil
self.displayingItemsUpdated?(false)
topItemNode.animateOut(completion: { [weak self, weak topItemNode] in topItemNode.animateOut(completion: { [weak self, weak topItemNode] in
topItemNode?.removeFromSupernode() topItemNode?.removeFromSupernode()
if let strongSelf = self, strongSelf.topItemAndNode == nil {
strongSelf.displayingItemsUpdated?(false)
}
}) })
} }
} }
} }
func enqueue(_ item: NotificationItem) { func enqueue(_ item: NotificationItem) {
var updatedDisplayingItems = false
if let (_, topItemNode) = self.topItemAndNode { if let (_, topItemNode) = self.topItemAndNode {
topItemNode.animateOut(completion: { [weak self, weak topItemNode] in topItemNode.animateOut(completion: { [weak self, weak topItemNode] in
topItemNode?.removeFromSupernode() topItemNode?.removeFromSupernode()
if let strongSelf = self, strongSelf.topItemAndNode == nil {
strongSelf.displayingItemsUpdated?(false)
}
}) })
} else {
updatedDisplayingItems = true
} }
var useCompactLayout = false var useCompactLayout = false
@ -138,9 +128,7 @@ final class NotificationContainerControllerNode: ASDisplayNode {
containerNode.animateIn() containerNode.animateIn()
} }
if updatedDisplayingItems { self.displayingItemsUpdated?(true)
self.displayingItemsUpdated?(true)
}
self.resetTimeoutTimer() self.resetTimeoutTimer()
} }
@ -172,12 +160,9 @@ final class NotificationContainerControllerNode: ASDisplayNode {
if let strongSelf = self { if let strongSelf = self {
if let (_, topItemNode) = strongSelf.topItemAndNode { if let (_, topItemNode) = strongSelf.topItemAndNode {
strongSelf.topItemAndNode = nil strongSelf.topItemAndNode = nil
strongSelf.displayingItemsUpdated?(false)
topItemNode.animateOut(completion: { [weak topItemNode] in topItemNode.animateOut(completion: { [weak topItemNode] in
topItemNode?.removeFromSupernode() topItemNode?.removeFromSupernode()
if let strongSelf = self, strongSelf.topItemAndNode == nil {
strongSelf.displayingItemsUpdated?(false)
}
}) })
} }
} }

View File

@ -842,10 +842,13 @@ public final class SharedAccountContextImpl: SharedAccountContext {
} else { } else {
text = presentationData.strings.Call_StatusBar("").0 text = presentationData.strings.Call_StatusBar("").0
} }
if let navigationController = self.mainWindow?.viewController as? NavigationController {
self.mainWindow?.setForceInCallStatusBar(text) navigationController.setForceInCallStatusBar(text)
}
} else { } else {
self.mainWindow?.setForceInCallStatusBar(nil) if let navigationController = self.mainWindow?.viewController as? NavigationController {
navigationController.setForceInCallStatusBar(nil)
}
} }
} }

View File

@ -94,16 +94,20 @@ public final class WalletSplashScreen: ViewController {
return return
} }
strongSelf.sendGrams(walletInfo: walletInfo, decryptedSecret: decryptedSecret, address: address, amount: amount, textMessage: textMessage, forceIfDestinationNotInitialized: false, randomId: randomId, serverSalt: serverSalt) strongSelf.sendGrams(walletInfo: walletInfo, decryptedSecret: decryptedSecret, address: address, amount: amount, textMessage: textMessage, forceIfDestinationNotInitialized: false, randomId: randomId, serverSalt: serverSalt)
}, error: { [weak self] _ in }, error: { [weak self] error in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
let text = strongSelf.presentationData.strings.Wallet_Send_ErrorDecryptionFailed if case .cancelled = error {
let controller = textAlertController(context: strongSelf.context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { strongSelf.dismiss()
self?.dismiss() } else {
})]) let text = strongSelf.presentationData.strings.Wallet_Send_ErrorDecryptionFailed
strongSelf.present(controller, in: .window(.root)) let controller = textAlertController(context: strongSelf.context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {
strongSelf.dismiss() self?.dismiss()
})])
strongSelf.present(controller, in: .window(.root))
strongSelf.dismiss()
}
}) })
case .sent: case .sent:
self.navigationItem.setLeftBarButton(UIBarButtonItem(customDisplayNode: ASDisplayNode())!, animated: false) self.navigationItem.setLeftBarButton(UIBarButtonItem(customDisplayNode: ASDisplayNode())!, animated: false)
@ -235,15 +239,18 @@ public final class WalletSplashScreen: ViewController {
strongSelf.mode = .created(walletInfo, wordList) strongSelf.mode = .created(walletInfo, wordList)
controller.dismiss() controller.dismiss()
strongSelf.push(WalletWordDisplayScreen(context: strongSelf.context, tonContext: strongSelf.tonContext, walletInfo: walletInfo, wordList: wordList, mode: .check, walletCreatedPreloadState: strongSelf.walletCreatedPreloadState)) strongSelf.push(WalletWordDisplayScreen(context: strongSelf.context, tonContext: strongSelf.tonContext, walletInfo: walletInfo, wordList: wordList, mode: .check, walletCreatedPreloadState: strongSelf.walletCreatedPreloadState))
}, error: { _ in }, error: { error in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
controller.dismiss() controller.dismiss()
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.presentationData.theme), title: strongSelf.presentationData.strings.Wallet_Created_ExportErrorTitle, text: strongSelf.presentationData.strings.Wallet_Created_ExportErrorText, actions: [ if case let .secretDecryptionFailed(.cancelled) = error {
TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { } else {
}) strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.presentationData.theme), title: strongSelf.presentationData.strings.Wallet_Created_ExportErrorTitle, text: strongSelf.presentationData.strings.Wallet_Created_ExportErrorText, actions: [
], actionLayout: .vertical), in: .window(.root)) TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {
})
], actionLayout: .vertical), in: .window(.root))
}
}) })
} }
case let .success(walletInfo): case let .success(walletInfo):
@ -720,16 +727,7 @@ private final class WalletSplashScreenNode: ViewControllerTracingNode {
let secondaryActionSize = self.secondaryActionTitleNode.updateLayout(CGSize(width: layout.size.width - sideInset * 2.0, height: layout.size.height)) let secondaryActionSize = self.secondaryActionTitleNode.updateLayout(CGSize(width: layout.size.width - sideInset * 2.0, height: layout.size.height))
let contentHeight = iconSize.height + iconSpacing + titleSize.height + titleSpacing + textSize.height let contentHeight = iconSize.height + iconSpacing + titleSize.height + titleSpacing + textSize.height
let contentVerticalOrigin = floor((layout.size.height - contentHeight - iconSize.height / 2.0) / 2.0) var contentVerticalOrigin = floor((layout.size.height - contentHeight - iconSize.height / 2.0) / 2.0)
let iconFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0), y: contentVerticalOrigin), size: iconSize).offsetBy(dx: iconOffset.x, dy: iconOffset.y)
transition.updateFrameAdditive(node: self.iconNode, frame: iconFrame)
self.animationNode.updateLayout(size: iconFrame.size)
transition.updateFrameAdditive(node: self.animationNode, frame: iconFrame)
let titleFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleSize.width) / 2.0), y: iconFrame.maxY + iconSpacing), size: titleSize)
transition.updateFrameAdditive(node: self.titleNode, frame: titleFrame)
let textFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - textSize.width) / 2.0), y: titleFrame.maxY + titleSpacing), size: textSize)
transition.updateFrameAdditive(node: self.textNode, frame: textFrame)
let minimalBottomInset: CGFloat = 60.0 let minimalBottomInset: CGFloat = 60.0
let bottomInset = layout.intrinsicInsets.bottom + max(minimalBottomInset, termsSize.height + termsSpacing * 2.0) let bottomInset = layout.intrinsicInsets.bottom + max(minimalBottomInset, termsSize.height + termsSpacing * 2.0)
@ -740,12 +738,27 @@ private final class WalletSplashScreenNode: ViewControllerTracingNode {
transition.updateFrame(node: self.buttonNode, frame: buttonFrame) transition.updateFrame(node: self.buttonNode, frame: buttonFrame)
self.buttonNode.updateLayout(width: buttonFrame.width, transition: transition) self.buttonNode.updateLayout(width: buttonFrame.width, transition: transition)
var maxContentVerticalOrigin = buttonFrame.minY - 12.0 - contentHeight
if !secondaryActionSize.width.isZero { if !secondaryActionSize.width.isZero {
let secondaryActionFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - secondaryActionSize.width) / 2.0), y: buttonFrame.minY - 20.0 - secondaryActionSize.height), size: secondaryActionSize) let secondaryActionFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - secondaryActionSize.width) / 2.0), y: buttonFrame.minY - 20.0 - secondaryActionSize.height), size: secondaryActionSize)
transition.updateFrameAdditive(node: self.secondaryActionTitleNode, frame: secondaryActionFrame) transition.updateFrameAdditive(node: self.secondaryActionTitleNode, frame: secondaryActionFrame)
transition.updateFrame(node: self.secondaryActionButtonNode, frame: secondaryActionFrame.insetBy(dx: -10.0, dy: -10.0)) transition.updateFrame(node: self.secondaryActionButtonNode, frame: secondaryActionFrame.insetBy(dx: -10.0, dy: -10.0))
maxContentVerticalOrigin = secondaryActionFrame.minY - 12.0 - contentHeight
} }
contentVerticalOrigin = min(contentVerticalOrigin, maxContentVerticalOrigin)
let iconFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0), y: contentVerticalOrigin), size: iconSize).offsetBy(dx: iconOffset.x, dy: iconOffset.y)
transition.updateFrameAdditive(node: self.iconNode, frame: iconFrame)
self.animationNode.updateLayout(size: iconFrame.size)
transition.updateFrameAdditive(node: self.animationNode, frame: iconFrame)
let titleFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleSize.width) / 2.0), y: iconFrame.maxY + iconSpacing), size: titleSize)
transition.updateFrameAdditive(node: self.titleNode, frame: titleFrame)
let textFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - textSize.width) / 2.0), y: titleFrame.maxY + titleSpacing), size: textSize)
transition.updateFrameAdditive(node: self.textNode, frame: textFrame)
let termsFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - termsSize.width) / 2.0), y: buttonFrame.maxY + floor((layout.size.height - layout.intrinsicInsets.bottom - buttonFrame.maxY - termsSize.height) / 2.0)), size: termsSize) let termsFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - termsSize.width) / 2.0), y: buttonFrame.maxY + floor((layout.size.height - layout.intrinsicInsets.bottom - buttonFrame.maxY - termsSize.height) / 2.0)), size: termsSize)
transition.updateFrameAdditive(node: self.termsNode, frame: termsFrame) transition.updateFrameAdditive(node: self.termsNode, frame: termsFrame)
} }