Persist more state when switching accounts

Closes #486
This commit is contained in:
Shadowfacts 2024-05-24 14:03:51 -04:00
parent 966a906436
commit 3d0de5af04
3 changed files with 31 additions and 14 deletions

View File

@ -225,7 +225,6 @@ class MainSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDelegate
window!.windowScene!.title = account.instanceURL.host! window!.windowScene!.title = account.instanceURL.host!
} }
let newRoot = createAppUI()
if let container = window?.rootViewController as? AccountSwitchingContainerViewController { if let container = window?.rootViewController as? AccountSwitchingContainerViewController {
let direction: AccountSwitchingContainerViewController.AnimationDirection let direction: AccountSwitchingContainerViewController.AnimationDirection
if animated, if animated,
@ -235,9 +234,9 @@ class MainSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDelegate
} else { } else {
direction = .none direction = .none
} }
container.setRoot(newRoot, for: account, animating: direction) container.setRoot(createAppUI, for: account, animating: direction)
} else { } else {
window!.rootViewController = AccountSwitchingContainerViewController(root: newRoot, for: account) window!.rootViewController = AccountSwitchingContainerViewController(root: createAppUI(), for: account)
} }
} }

View File

@ -23,7 +23,7 @@ class AccountSwitchingContainerViewController: UIViewController {
private(set) var currentAccountID: String private(set) var currentAccountID: String
private(set) var root: AccountSwitchableViewController private(set) var root: AccountSwitchableViewController
private var userActivities: [String: NSUserActivity] = [:] private var viewControllers: [String: (AccountSwitchableViewController?, NSUserActivity)] = [:]
init(root: AccountSwitchableViewController, for account: UserAccountInfo) { init(root: AccountSwitchableViewController, for account: UserAccountInfo) {
self.currentAccountID = account.id self.currentAccountID = account.id
@ -42,27 +42,43 @@ class AccountSwitchingContainerViewController: UIViewController {
embedChild(root) embedChild(root)
} }
func setRoot(_ newRoot: AccountSwitchableViewController, for account: UserAccountInfo, animating direction: AnimationDirection) { override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
viewControllers = viewControllers.mapValues { (_, activity) in
(nil, activity)
}
}
func setRoot(_ newRootProvider: () -> AccountSwitchableViewController, for account: UserAccountInfo, animating direction: AnimationDirection) {
let oldRoot = self.root let oldRoot = self.root
if direction == .none { if direction == .none {
oldRoot.removeViewAndController() oldRoot.removeViewAndController()
} }
if let activity = oldRoot.stateRestorationActivity() { if let activity = oldRoot.stateRestorationActivity() {
stateRestorationLogger.debug("AccountSwitchingContainer: saving \(activity.activityType, privacy: .public) for \(self.currentAccountID, privacy: .public)") stateRestorationLogger.debug("AccountSwitchingContainer: saving \(activity.activityType, privacy: .public) for \(self.currentAccountID, privacy: .public)")
userActivities[currentAccountID] = activity viewControllers[currentAccountID] = (oldRoot, activity)
}
let newRoot: AccountSwitchableViewController
if let (existingRoot, activity) = viewControllers.removeValue(forKey: account.id) {
if let existingRoot {
newRoot = existingRoot
stateRestorationLogger.debug("AccountSwitchingContainer: reusing existing VC for \(account.id, privacy: .public)")
} else {
newRoot = newRootProvider()
stateRestorationLogger.debug("AccountSwitchingContainer: restoring \(activity.activityType, privacy: .public) for \(account.id, privacy: .public)")
let context = StateRestorationUserActivityHandlingContext(root: newRoot)
_ = activity.handleResume(manager: UserActivityManager(scene: view.window!.windowScene!, context: context))
context.finalize(activity: activity)
}
} else {
newRoot = newRootProvider()
} }
self.currentAccountID = account.id self.currentAccountID = account.id
self.root = newRoot self.root = newRoot
embedChild(newRoot) embedChild(newRoot)
if let activity = userActivities.removeValue(forKey: account.id) {
stateRestorationLogger.debug("AccountSwitchingContainer: restoring \(activity.activityType, privacy: .public) for \(account.id, privacy: .public)")
let context = StateRestorationUserActivityHandlingContext(root: newRoot)
_ = activity.handleResume(manager: UserActivityManager(scene: view.window!.windowScene!, context: context))
context.finalize(activity: activity)
}
if direction != .none { if direction != .none {
if UIAccessibility.prefersCrossFadeTransitions { if UIAccessibility.prefersCrossFadeTransitions {
newRoot.view.alpha = 0 newRoot.view.alpha = 0
@ -92,6 +108,7 @@ class AccountSwitchingContainerViewController: UIViewController {
#endif #endif
// only one edge is affected in each direction, i have no idea why // only one edge is affected in each direction, i have no idea why
let origAdditionalSafeAreaInsets = oldRoot.additionalSafeAreaInsets
if direction == .upwards { if direction == .upwards {
oldRoot.additionalSafeAreaInsets.bottom = view.safeAreaInsets.bottom oldRoot.additionalSafeAreaInsets.bottom = view.safeAreaInsets.bottom
} else { } else {
@ -102,6 +119,7 @@ class AccountSwitchingContainerViewController: UIViewController {
oldRoot.view.transform = CGAffineTransform(translationX: 0, y: -newInitialOffset).scaledBy(x: scale, y: scale) oldRoot.view.transform = CGAffineTransform(translationX: 0, y: -newInitialOffset).scaledBy(x: scale, y: scale)
newRoot.view.transform = .identity newRoot.view.transform = .identity
} completion: { (_) in } completion: { (_) in
oldRoot.additionalSafeAreaInsets = origAdditionalSafeAreaInsets
oldRoot.removeViewAndController() oldRoot.removeViewAndController()
newRoot.view.layer.masksToBounds = false newRoot.view.layer.masksToBounds = false
} }

View File

@ -68,7 +68,7 @@ extension UIView {
if layout { if layout {
subview.frame = bounds subview.frame = bounds
subview.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
subview.leadingAnchor.constraint(equalTo: leadingAnchor), subview.leadingAnchor.constraint(equalTo: leadingAnchor),
subview.trailingAnchor.constraint(equalTo: trailingAnchor), subview.trailingAnchor.constraint(equalTo: trailingAnchor),