Add landscape layout for passcode screen to be used in share extension

This commit is contained in:
Ilya Laktyushin 2019-10-20 23:39:24 +04:00
parent ee68b7b539
commit 50a4f47718
5 changed files with 152 additions and 72 deletions

View File

@ -167,10 +167,6 @@ final class PasscodeEntryControllerNode: ASDisplayNode {
} }
var size = validLayout.size var size = validLayout.size
if case .compact = validLayout.metrics.widthClass, size.width > size.height {
size = CGSize(width: size.height, height: size.width)
}
if let background = self.background, background.size == size { if let background = self.background, background.size == size {
return return
} }
@ -333,36 +329,11 @@ final class PasscodeEntryControllerNode: ASDisplayNode {
self.validLayout = layout self.validLayout = layout
self.updateBackground() self.updateBackground()
if layout.size.width == 320.0 {
self.iconNode.alpha = 0.0
}
let bounds = CGRect(origin: CGPoint(), size: layout.size) let bounds = CGRect(origin: CGPoint(), size: layout.size)
transition.updateFrame(node: self.backgroundNode, frame: bounds) transition.updateFrame(node: self.backgroundNode, frame: bounds)
transition.updateFrame(view: self.effectView, frame: bounds) transition.updateFrame(view: self.effectView, frame: bounds)
let iconSize = CGSize(width: 35.0, height: 37.0)
transition.updateFrame(node: self.iconNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0) + 6.0, y: layout.insets(options: .statusBar).top + 15.0), size: iconSize))
let passcodeLayout = PasscodeLayout(layout: layout)
let inputFieldFrame = self.inputFieldNode.updateLayout(layout: passcodeLayout.layout, topOffset: passcodeLayout.inputFieldOffset, transition: transition)
transition.updateFrame(node: self.inputFieldNode, frame: CGRect(origin: CGPoint(), size: layout.size))
let titleSize = self.titleNode.updateLayout(layout: layout, transition: transition)
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: 0.0, y: passcodeLayout.titleOffset), size: titleSize))
var subtitleOffset = passcodeLayout.subtitleOffset
if case .alphanumeric = self.passcodeType {
subtitleOffset = 16.0
}
let subtitleSize = self.subtitleNode.updateLayout(layout: layout, transition: transition)
transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(x: 0.0, y: inputFieldFrame.maxY + subtitleOffset), size: subtitleSize))
let (keyboardFrame, keyboardButtonSize) = self.keyboardNode.updateLayout(layout: passcodeLayout, transition: transition)
transition.updateFrame(node: self.keyboardNode, frame: CGRect(origin: CGPoint(), size: layout.size))
switch self.passcodeType { switch self.passcodeType {
case .digits6, .digits4: case .digits6, .digits4:
self.keyboardNode.alpha = 1.0 self.keyboardNode.alpha = 1.0
@ -372,22 +343,91 @@ final class PasscodeEntryControllerNode: ASDisplayNode {
self.deleteButtonNode.alpha = 0.0 self.deleteButtonNode.alpha = 0.0
} }
let isLandscape = layout.orientation == .landscape && layout.deviceMetrics.type != .tablet
let keyboardHidden = self.keyboardNode.alpha == 0.0
let layoutSize: CGSize
if isLandscape {
if keyboardHidden {
layoutSize = CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right, height: layout.size.height)
} else {
layoutSize = CGSize(width: layout.size.width / 2.0, height: layout.size.height)
}
} else {
layoutSize = layout.size
}
if layout.size.width == 320.0 || (isLandscape && keyboardHidden) {
self.iconNode.alpha = 0.0
}
let passcodeLayout = PasscodeLayout(layout: layout)
let inputFieldOffset: CGFloat
if isLandscape {
let bottomInset = layout.inputHeight ?? 0.0
if !keyboardHidden || bottomInset == 0.0 {
inputFieldOffset = floor(layoutSize.height / 2.0 + 12.0)
} else {
inputFieldOffset = floor(layoutSize.height - bottomInset) / 2.0 - 40.0
}
} else {
inputFieldOffset = passcodeLayout.inputFieldOffset
}
let inputFieldFrame = self.inputFieldNode.updateLayout(size: layoutSize, topOffset: inputFieldOffset, transition: transition)
transition.updateFrame(node: self.inputFieldNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left, y: 0.0), size: layoutSize))
let titleFrame: CGRect
if isLandscape {
let titleSize = self.titleNode.updateLayout(size: CGSize(width: layoutSize.width, height: layout.size.height), transition: transition)
titleFrame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: inputFieldFrame.minY - titleSize.height - 16.0), size: titleSize)
} else {
let titleSize = self.titleNode.updateLayout(size: layout.size, transition: transition)
titleFrame = CGRect(origin: CGPoint(x: 0.0, y: passcodeLayout.titleOffset), size: titleSize)
}
transition.updateFrame(node: self.titleNode, frame: titleFrame)
let iconSize = CGSize(width: 35.0, height: 37.0)
let iconFrame: CGRect
if isLandscape {
iconFrame = CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((layoutSize.width - iconSize.width) / 2.0) + 6.0, y: titleFrame.minY - iconSize.height - 14.0), size: iconSize)
} else {
iconFrame = CGRect(origin: CGPoint(x: floor((layoutSize.width - iconSize.width) / 2.0) + 6.0, y: layout.insets(options: .statusBar).top + 15.0), size: iconSize)
}
transition.updateFrame(node: self.iconNode, frame: iconFrame)
var subtitleOffset = passcodeLayout.subtitleOffset
if case .alphanumeric = self.passcodeType {
subtitleOffset = 16.0
}
let subtitleSize = self.subtitleNode.updateLayout(size: layoutSize, transition: transition)
transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left, y: inputFieldFrame.maxY + subtitleOffset), size: subtitleSize))
let (keyboardFrame, keyboardButtonSize) = self.keyboardNode.updateLayout(layout: passcodeLayout, transition: transition)
transition.updateFrame(node: self.keyboardNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: layout.size))
let bottomInset = layout.inputHeight ?? 0.0 let bottomInset = layout.inputHeight ?? 0.0
let cancelSize = self.cancelButtonNode.measure(layout.size) let cancelSize = self.cancelButtonNode.measure(layout.size)
var cancelY: CGFloat = layout.size.height - layout.intrinsicInsets.bottom - cancelSize.height - passcodeLayout.keyboard.deleteOffset var bottomButtonY = layout.size.height - layout.intrinsicInsets.bottom - cancelSize.height - passcodeLayout.keyboard.deleteOffset
if bottomInset > 0 && self.keyboardNode.alpha < 1.0 { var cancelX = floor(keyboardFrame.minX + keyboardButtonSize.width / 2.0 - cancelSize.width / 2.0)
cancelY = layout.size.height - bottomInset - cancelSize.height - 20.0 var cancelY = bottomButtonY
if bottomInset > 0 && keyboardHidden {
cancelX = floor((layout.size.width - cancelSize.width) / 2.0)
cancelY = layout.size.height - bottomInset - cancelSize.height - 15.0 - layout.intrinsicInsets.bottom
} else if isLandscape {
bottomButtonY = keyboardFrame.maxY - keyboardButtonSize.height + floor((keyboardButtonSize.height - cancelSize.height) / 2.0)
cancelY = bottomButtonY
} }
transition.updateFrame(node: self.cancelButtonNode, frame: CGRect(origin: CGPoint(x: floor(keyboardFrame.minX + keyboardButtonSize.width / 2.0 - cancelSize.width / 2.0), y: cancelY), size: cancelSize)) transition.updateFrame(node: self.cancelButtonNode, frame: CGRect(origin: CGPoint(x: cancelX, y: cancelY), size: cancelSize))
let deleteSize = self.deleteButtonNode.measure(layout.size) let deleteSize = self.deleteButtonNode.measure(layout.size)
transition.updateFrame(node: self.deleteButtonNode, frame: CGRect(origin: CGPoint(x: floor(keyboardFrame.maxX - keyboardButtonSize.width / 2.0 - deleteSize.width / 2.0), y: layout.size.height - layout.intrinsicInsets.bottom - deleteSize.height - passcodeLayout.keyboard.deleteOffset), size: deleteSize)) transition.updateFrame(node: self.deleteButtonNode, frame: CGRect(origin: CGPoint(x: floor(keyboardFrame.maxX - keyboardButtonSize.width / 2.0 - deleteSize.width / 2.0), y: bottomButtonY), size: deleteSize))
if let biometricIcon = self.biometricButtonNode.image(for: .normal) { if let biometricIcon = self.biometricButtonNode.image(for: .normal) {
var biometricY: CGFloat = 0.0 var biometricY: CGFloat = 0.0
if bottomInset > 0 && self.keyboardNode.alpha < 1.0 { if bottomInset > 0 && keyboardHidden {
biometricY = inputFieldFrame.maxY + floor((layout.size.height - bottomInset - inputFieldFrame.maxY - biometricIcon.size.height) / 2.0) biometricY = inputFieldFrame.maxY + floor((layout.size.height - bottomInset - inputFieldFrame.maxY - biometricIcon.size.height) / 2.0)
} else { } else {
biometricY = keyboardFrame.maxY + passcodeLayout.keyboard.biometricsOffset biometricY = keyboardFrame.maxY + passcodeLayout.keyboard.biometricsOffset

View File

@ -58,7 +58,7 @@ private func generateButtonImage(background: PasscodeBackground, frame: CGRect,
titleOffset = -11.0 titleOffset = -11.0
} }
subtitleOffset = -54.0 subtitleOffset = -54.0
} else { } else if size.width > 70.0 {
titleFont = regularTitleFont titleFont = regularTitleFont
subtitleFont = regularSubtitleFont subtitleFont = regularSubtitleFont
if subtitle.isEmpty { if subtitle.isEmpty {
@ -68,6 +68,16 @@ private func generateButtonImage(background: PasscodeBackground, frame: CGRect,
} }
subtitleOffset = -48.0 subtitleOffset = -48.0
} }
else {
titleFont = regularTitleFont
subtitleFont = regularSubtitleFont
if subtitle.isEmpty {
titleOffset = -11.0
} else {
titleOffset = -4.0
}
subtitleOffset = -41.0
}
let titlePath = CGMutablePath() let titlePath = CGMutablePath()
titlePath.addRect(bounds.offsetBy(dx: 0.0, dy: titleOffset)) titlePath.addRect(bounds.offsetBy(dx: 0.0, dy: titleOffset))
@ -236,36 +246,66 @@ final class PasscodeEntryKeyboardNode: ASDisplayNode {
} }
func updateLayout(layout: PasscodeLayout, transition: ContainedViewLayoutTransition) -> (CGRect, CGSize) { func updateLayout(layout: PasscodeLayout, transition: ContainedViewLayoutTransition) -> (CGRect, CGSize) {
let origin = CGPoint(x: floor((layout.layout.size.width - layout.keyboard.size.width) / 2.0), y: layout.keyboard.topOffset) let origin: CGPoint
let buttonSize: CGFloat
let horizontalSecond: CGFloat
let horizontalThird: CGFloat
let verticalSecond: CGFloat
let verticalThird: CGFloat
let verticalFourth: CGFloat
let keyboardSize: CGSize
if layout.layout.orientation == .landscape && layout.layout.deviceMetrics.type != .tablet {
let horizontalSpacing: CGFloat = 20.0
let verticalSpacing: CGFloat = 12.0
buttonSize = 65.0
keyboardSize = CGSize(width: buttonSize * 3.0 + horizontalSpacing * 2.0, height: buttonSize * 4.0 + verticalSpacing * 3.0)
horizontalSecond = buttonSize + horizontalSpacing
horizontalThird = buttonSize * 2.0 + horizontalSpacing * 2.0
verticalSecond = buttonSize + verticalSpacing
verticalThird = buttonSize * 2.0 + verticalSpacing * 2.0
verticalFourth = buttonSize * 3.0 + verticalSpacing * 3.0
origin = CGPoint(x: floor(layout.layout.size.width / 2.0 + (layout.layout.size.width / 2.0 - keyboardSize.width) / 2.0) - layout.layout.safeInsets.right, y: floor((layout.layout.size.height - keyboardSize.height) / 2.0))
} else {
origin = CGPoint(x: floor((layout.layout.size.width - layout.keyboard.size.width) / 2.0), y: layout.keyboard.topOffset)
buttonSize = layout.keyboard.buttonSize
horizontalSecond = layout.keyboard.horizontalSecond
horizontalThird = layout.keyboard.horizontalThird
verticalSecond = layout.keyboard.verticalSecond
verticalThird = layout.keyboard.verticalThird
verticalFourth = layout.keyboard.verticalFourth
keyboardSize = layout.keyboard.size
}
if let subnodes = self.subnodes { if let subnodes = self.subnodes {
for i in 0 ..< subnodes.count { for i in 0 ..< subnodes.count {
var origin = origin var origin = origin
if i % 3 == 0 { if i % 3 == 0 {
origin.x += 0.0 origin.x += 0.0
} else if (i % 3 == 1) { } else if (i % 3 == 1) {
origin.x += layout.keyboard.horizontalSecond origin.x += horizontalSecond
} }
else { else {
origin.x += layout.keyboard.horizontalThird origin.x += horizontalThird
} }
if i / 3 == 0 { if i / 3 == 0 {
origin.y += 0.0 origin.y += 0.0
} }
else if i / 3 == 1 { else if i / 3 == 1 {
origin.y += layout.keyboard.verticalSecond origin.y += verticalSecond
} }
else if i / 3 == 2 { else if i / 3 == 2 {
origin.y += layout.keyboard.verticalThird origin.y += verticalThird
} }
else if i / 3 == 3 { else if i / 3 == 3 {
origin.x += layout.keyboard.horizontalSecond origin.x += horizontalSecond
origin.y += layout.keyboard.verticalFourth origin.y += verticalFourth
} }
transition.updateFrame(node: subnodes[i], frame: CGRect(origin: origin, size: CGSize(width: layout.keyboard.buttonSize, height: layout.keyboard.buttonSize))) transition.updateFrame(node: subnodes[i], frame: CGRect(origin: origin, size: CGSize(width: buttonSize, height: buttonSize)))
} }
} }
return (CGRect(origin: origin, size: layout.keyboard.size), CGSize(width: layout.keyboard.buttonSize, height: layout.keyboard.buttonSize)) return (CGRect(origin: origin, size: keyboardSize), CGSize(width: buttonSize, height: buttonSize))
} }
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

View File

@ -13,7 +13,7 @@ final class PasscodeEntryLabelNode: ASDisplayNode {
private let wrapperNode: ASDisplayNode private let wrapperNode: ASDisplayNode
private let textNode: ASTextNode private let textNode: ASTextNode
private var validLayout: ContainerViewLayout? private var validLayout: CGSize?
override init() { override init() {
self.wrapperNode = ASDisplayNode() self.wrapperNode = ASDisplayNode()
@ -34,13 +34,13 @@ final class PasscodeEntryLabelNode: ASDisplayNode {
self.textNode.attributedText = text self.textNode.attributedText = text
completion() completion()
if let validLayout = self.validLayout { if let size = self.validLayout {
let _ = self.updateLayout(layout: validLayout, transition: .immediate) let _ = self.updateLayout(size: size, transition: .immediate)
} }
case .slideIn: case .slideIn:
self.textNode.attributedText = text self.textNode.attributedText = text
if let validLayout = self.validLayout { if let size = self.validLayout {
let _ = self.updateLayout(layout: validLayout, transition: .immediate) let _ = self.updateLayout(size: size, transition: .immediate)
} }
let offset = self.wrapperNode.bounds.width / 2.0 let offset = self.wrapperNode.bounds.width / 2.0
@ -61,29 +61,29 @@ final class PasscodeEntryLabelNode: ASDisplayNode {
self.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, completion: { _ in self.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, completion: { _ in
completion() completion()
}) })
if let validLayout = self.validLayout { if let size = self.validLayout {
let _ = self.updateLayout(layout: validLayout, transition: .immediate) let _ = self.updateLayout(size: size, transition: .immediate)
} }
}) })
} else { } else {
self.textNode.attributedText = text self.textNode.attributedText = text
self.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) self.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
completion() completion()
if let validLayout = self.validLayout { if let size = self.validLayout {
let _ = self.updateLayout(layout: validLayout, transition: .immediate) let _ = self.updateLayout(size: size, transition: .immediate)
} }
} }
} }
} }
func updateLayout(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) -> CGSize { func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
self.validLayout = layout self.validLayout = size
let textSize = self.textNode.measure(layout.size) let textSize = self.textNode.measure(size)
let textFrame = CGRect(x: floor((layout.size.width - textSize.width) / 2.0), y: 0.0, width: textSize.width, height: textSize.height) let textFrame = CGRect(x: floor((size.width - textSize.width) / 2.0), y: 0.0, width: textSize.width, height: textSize.height)
transition.updateFrame(node: self.wrapperNode, frame: textFrame) transition.updateFrame(node: self.wrapperNode, frame: textFrame)
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(), size: textSize)) transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(), size: textSize))
return CGSize(width: layout.size.width, height: 25.0) return CGSize(width: size.width, height: 25.0)
} }
} }

View File

@ -139,7 +139,7 @@ public final class PasscodeInputFieldNode: ASDisplayNode, UITextFieldDelegate {
private let borderNode: ASImageNode private let borderNode: ASImageNode
private let dotNodes: [PasscodeEntryDotNode] private let dotNodes: [PasscodeEntryDotNode]
private var validLayout: (ContainerViewLayout, CGFloat)? private var validLayout: (CGSize, CGFloat)?
public var complete: ((String) -> Void)? public var complete: ((String) -> Void)?
@ -202,15 +202,15 @@ public final class PasscodeInputFieldNode: ASDisplayNode, UITextFieldDelegate {
self.textFieldNode.textField.keyboardType = self.fieldType.keyboardType self.textFieldNode.textField.keyboardType = self.fieldType.keyboardType
if let (layout, topOffset) = self.validLayout { if let (size, topOffset) = self.validLayout {
let _ = self.updateLayout(layout: layout, topOffset: topOffset, transition: animated ? .animated(duration: 0.25, curve: .easeInOut) : .immediate) let _ = self.updateLayout(size: size, topOffset: topOffset, transition: animated ? .animated(duration: 0.25, curve: .easeInOut) : .immediate)
} }
} }
func updateBackground(_ image: UIImage, size: CGSize) { func updateBackground(_ image: UIImage, size: CGSize) {
self.background = (image, size) self.background = (image, size)
if let (layout, topOffset) = self.validLayout { if let (size, topOffset) = self.validLayout {
let _ = self.updateLayout(layout: layout, topOffset: topOffset, transition: .immediate) let _ = self.updateLayout(size: size, topOffset: topOffset, transition: .immediate)
} }
} }
@ -302,13 +302,13 @@ public final class PasscodeInputFieldNode: ASDisplayNode, UITextFieldDelegate {
self.textFieldNode.textField.text = "" self.textFieldNode.textField.text = ""
} }
self.fieldType = fieldType self.fieldType = fieldType
if let (layout, topOffset) = self.validLayout { if let (size, topOffset) = self.validLayout {
let _ = self.updateLayout(layout: layout, topOffset: topOffset, transition: .immediate) let _ = self.updateLayout(size: size, topOffset: topOffset, transition: .immediate)
} }
} }
public func updateLayout(layout: ContainerViewLayout, topOffset: CGFloat, transition: ContainedViewLayoutTransition) -> CGRect { public func updateLayout(size: CGSize, topOffset: CGFloat, transition: ContainedViewLayoutTransition) -> CGRect {
self.validLayout = (layout, topOffset) self.validLayout = (size, topOffset)
let fieldAlpha: CGFloat let fieldAlpha: CGFloat
switch self.fieldType { switch self.fieldType {
@ -321,7 +321,7 @@ public final class PasscodeInputFieldNode: ASDisplayNode, UITextFieldDelegate {
transition.updateAlpha(node: self.textFieldNode, alpha: fieldAlpha) transition.updateAlpha(node: self.textFieldNode, alpha: fieldAlpha)
transition.updateAlpha(node: self.borderNode, alpha: fieldAlpha) transition.updateAlpha(node: self.borderNode, alpha: fieldAlpha)
let origin = CGPoint(x: floor((layout.size.width - dotDiameter * 6 - dotSpacing * 5) / 2.0), y: topOffset) let origin = CGPoint(x: floor((size.width - dotDiameter * 6 - dotSpacing * 5) / 2.0), y: topOffset)
for i in 0 ..< self.dotNodes.count { for i in 0 ..< self.dotNodes.count {
let node = self.dotNodes[i] let node = self.dotNodes[i]
let dotAlpha: CGFloat let dotAlpha: CGFloat
@ -343,7 +343,7 @@ public final class PasscodeInputFieldNode: ASDisplayNode, UITextFieldDelegate {
if !self.useCustomNumpad { if !self.useCustomNumpad {
inset = 16.0 inset = 16.0
} }
let fieldFrame = CGRect(x: inset, y: origin.y, width: layout.size.width - inset * 2.0, height: fieldHeight) let fieldFrame = CGRect(x: inset, y: origin.y, width: size.width - inset * 2.0, height: fieldHeight)
transition.updateFrame(node: self.borderNode, frame: fieldFrame) transition.updateFrame(node: self.borderNode, frame: fieldFrame)
transition.updateFrame(node: self.textFieldNode, frame: fieldFrame.insetBy(dx: 13.0, dy: 0.0)) transition.updateFrame(node: self.textFieldNode, frame: fieldFrame.insetBy(dx: 13.0, dy: 0.0))
if let (backgroundImage, backgroundSize) = self.background { if let (backgroundImage, backgroundSize) = self.background {

View File

@ -146,7 +146,7 @@ final class PasscodeSetupControllerNode: ASDisplayNode {
self.wrapperNode.frame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: layout.size.height) self.wrapperNode.frame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: layout.size.height)
let inputFieldFrame = self.inputFieldNode.updateLayout(layout: layout, topOffset: floor(insets.top + navigationBarHeight + (layout.size.height - navigationBarHeight - insets.top - insets.bottom - 24.0) / 2.0), transition: transition) let inputFieldFrame = self.inputFieldNode.updateLayout(size: layout.size, topOffset: floor(insets.top + navigationBarHeight + (layout.size.height - navigationBarHeight - insets.top - insets.bottom - 24.0) / 2.0), transition: transition)
transition.updateFrame(node: self.inputFieldNode, frame: CGRect(origin: CGPoint(), size: layout.size)) transition.updateFrame(node: self.inputFieldNode, frame: CGRect(origin: CGPoint(), size: layout.size))
transition.updateFrame(node: self.inputFieldBackgroundNode, frame: CGRect(x: 0.0, y: inputFieldFrame.minY - 6.0, width: layout.size.width, height: 48.0)) transition.updateFrame(node: self.inputFieldBackgroundNode, frame: CGRect(x: 0.0, y: inputFieldFrame.minY - 6.0, width: layout.size.width, height: 48.0))