Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS 17 state restoration crash fix #767

Merged
merged 5 commits into from
Sep 20, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 49 additions & 46 deletions Zotero/Scenes/Master/MasterContainerViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ final class MasterContainerViewController: UINavigationController {
lazy var bottomController: DraggableViewController? = {
return coordinatorDelegate?.createBottomController()
}()
private var bottomContainer: UIView?
private var bottomYConstraint: NSLayoutConstraint!
private var bottomContainerBottomConstraint: NSLayoutConstraint!
private weak var bottomContainer: UIView?
private weak var bottomYConstraint: NSLayoutConstraint?
private weak var bottomContainerBottomConstraint: NSLayoutConstraint?
mvasilak marked this conversation as resolved.
Show resolved Hide resolved
// Current position of bottom container
private var bottomPosition: BottomPosition
// Previous position of bottom container. Used to return to previous position when drag handle is tapped.
Expand Down Expand Up @@ -78,31 +78,11 @@ final class MasterContainerViewController: UINavigationController {
func setupView() {
guard let bottomController else { return }

let bottomPanRecognizer = UIPanGestureRecognizer()
bottomPanRecognizer.delegate = self
bottomPanRecognizer.rx.event
.subscribe(with: self, onNext: { _, recognizer in
toolbarDidPan(recognizer: recognizer)
})
.disposed(by: disposeBag)

let tapRecognizer = UITapGestureRecognizer()
tapRecognizer.delegate = self
tapRecognizer.require(toFail: bottomPanRecognizer)
tapRecognizer.rx.event
.subscribe(with: self, onNext: { _, _ in
toggleBottomPosition()
})
.disposed(by: disposeBag)

let bottomContainer = UIView()
bottomContainer.translatesAutoresizingMaskIntoConstraints = false
bottomContainer.layer.masksToBounds = true
bottomContainer.backgroundColor = .systemBackground
bottomContainer.addGestureRecognizer(bottomPanRecognizer)
bottomContainer.addGestureRecognizer(tapRecognizer)
view.addSubview(bottomContainer)
self.bottomContainer = bottomContainer

let handleBackground = UIView()
handleBackground.translatesAutoresizingMaskIntoConstraints = false
Expand Down Expand Up @@ -160,13 +140,34 @@ final class MasterContainerViewController: UINavigationController {
bottomControllerBottom
])

self.bottomContainer = bottomContainer
self.bottomYConstraint = bottomYConstraint
self.bottomContainerBottomConstraint = bottomContainerBottomConstraint

let bottomPanRecognizer = UIPanGestureRecognizer()
bottomPanRecognizer.delegate = self
bottomPanRecognizer.rx.event
.subscribe(with: self, onNext: { _, recognizer in
toolbarDidPan(recognizer: recognizer)
})
.disposed(by: disposeBag)

let tapRecognizer = UITapGestureRecognizer()
tapRecognizer.delegate = self
tapRecognizer.require(toFail: bottomPanRecognizer)
tapRecognizer.rx.event
.subscribe(with: self, onNext: { _, _ in
toggleBottomPosition()
})
.disposed(by: disposeBag)

bottomContainer.addGestureRecognizer(bottomPanRecognizer)
bottomContainer.addGestureRecognizer(tapRecognizer)

func toolbarDidPan(recognizer: UIPanGestureRecognizer) {
switch recognizer.state {
case .began:
initialBottomMinY = self.bottomContainer?.frame.minY ?? 0
initialBottomMinY = bottomContainer.frame.minY
bottomController.disablePanning()

case .changed:
Expand All @@ -183,14 +184,14 @@ final class MasterContainerViewController: UINavigationController {
minY = hiddenTopOffset
}

self.bottomYConstraint.constant = minY
bottomYConstraint.constant = minY
view.layoutIfNeeded()

case .ended, .failed:
let availableHeight = view.frame.height - keyboardHeight
let dragVelocity = recognizer.velocity(in: view)
let newPosition = position(fromYPos: self.bottomYConstraint.constant, containerHeight: availableHeight, velocity: dragVelocity)
let velocity = velocity(from: dragVelocity, currentYPos: self.bottomYConstraint.constant, position: newPosition, availableHeight: availableHeight)
let newPosition = position(fromYPos: bottomYConstraint.constant, containerHeight: availableHeight, velocity: dragVelocity)
let velocity = velocity(from: dragVelocity, currentYPos: bottomYConstraint.constant, position: newPosition, availableHeight: availableHeight)

set(bottomPosition: newPosition, containerHeight: availableHeight)

Expand Down Expand Up @@ -266,30 +267,30 @@ final class MasterContainerViewController: UINavigationController {

func setupKeyboardObserving() {
NotificationCenter.default
.keyboardWillShow
.observe(on: MainScheduler.instance)
.subscribe(onNext: { notification in
if let data = notification.keyboardData {
setupKeyboard(with: data)
}
})
.disposed(by: disposeBag)
.keyboardWillShow
.observe(on: MainScheduler.instance)
.subscribe(onNext: { notification in
if let data = notification.keyboardData {
setupKeyboard(with: data)
}
})
.disposed(by: disposeBag)

NotificationCenter.default
.keyboardWillHide
.observe(on: MainScheduler.instance)
.subscribe(onNext: { notification in
if let data = notification.keyboardData {
setupKeyboard(with: data)
}
})
.disposed(by: disposeBag)
.keyboardWillHide
.observe(on: MainScheduler.instance)
.subscribe(onNext: { notification in
if let data = notification.keyboardData {
setupKeyboard(with: data)
}
})
.disposed(by: disposeBag)

func setupKeyboard(with keyboardData: KeyboardData) {
keyboardHeight = keyboardData.visibleHeight

updateBottomPosition()
bottomContainerBottomConstraint.constant = keyboardData.visibleHeight
bottomContainerBottomConstraint?.constant = keyboardData.visibleHeight
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
})
Expand All @@ -302,7 +303,7 @@ final class MasterContainerViewController: UINavigationController {

updateBottomPosition()
if let splitViewController {
// Split view controller collapsed status when the app launches is correct here, so it's used to show/hide bottom sheet for the first appearance.
// Split view controller collapsed status when the app launches is correct here, so it's used to show/hide bottom sheet for the first appearance.q2
// The app may be launched in collapsed mode, if it was in such mode the last time it was moved to background.
setBottomSheet(hidden: splitViewController.isCollapsed)
}
Expand Down Expand Up @@ -348,7 +349,7 @@ final class MasterContainerViewController: UINavigationController {
}

private func set(bottomPosition: BottomPosition, containerHeight: CGFloat) {
bottomYConstraint.constant = bottomPosition.topOffset(availableHeight: containerHeight)
bottomYConstraint?.constant = bottomPosition.topOffset(availableHeight: containerHeight)
self.bottomPosition = bottomPosition
}

Expand All @@ -364,6 +365,8 @@ final class MasterContainerViewController: UINavigationController {

extension MasterContainerViewController: UIGestureRecognizerDelegate {
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
guard let bottomContainer else { return false }

let location = gestureRecognizer.location(in: bottomContainer)

if gestureRecognizer is UITapGestureRecognizer {
Expand Down