forked from shadowfacts/Tusker
Add account switching animation
This commit is contained in:
parent
904ff4eecf
commit
75d26e613b
|
@ -76,7 +76,6 @@ public class Client {
|
|||
return
|
||||
}
|
||||
guard let result = try? Client.decoder.decode(Result.self, from: data) else {
|
||||
print(request)
|
||||
completion(.failure(.invalidModel))
|
||||
return
|
||||
}
|
||||
|
|
|
@ -297,6 +297,7 @@
|
|||
D6F2E966249E8BFD005846BB /* CrashReporterViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6F2E964249E8BFD005846BB /* CrashReporterViewController.xib */; };
|
||||
D6F953EC212519E700CF0F2B /* TimelineTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F953EB212519E700CF0F2B /* TimelineTableViewController.swift */; };
|
||||
D6F953F021251A2900CF0F2B /* MastodonController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F953EF21251A2900CF0F2B /* MastodonController.swift */; };
|
||||
D6FF9860255C717400845181 /* AccountSwitchingContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6FF985F255C717400845181 /* AccountSwitchingContainerViewController.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
@ -649,6 +650,7 @@
|
|||
D6F2E964249E8BFD005846BB /* CrashReporterViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CrashReporterViewController.xib; sourceTree = "<group>"; };
|
||||
D6F953EB212519E700CF0F2B /* TimelineTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineTableViewController.swift; sourceTree = "<group>"; };
|
||||
D6F953EF21251A2900CF0F2B /* MastodonController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonController.swift; sourceTree = "<group>"; };
|
||||
D6FF985F255C717400845181 /* AccountSwitchingContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSwitchingContainerViewController.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -975,6 +977,7 @@
|
|||
D641C782213DD7F0004B4513 /* Main */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D6FF985F255C717400845181 /* AccountSwitchingContainerViewController.swift */,
|
||||
D6F0B12A24A3071C001E48C3 /* MainSplitViewController.swift */,
|
||||
04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */,
|
||||
D6F0B17424A3A1AA001E48C3 /* MainSidebarViewController.swift */,
|
||||
|
@ -1971,6 +1974,7 @@
|
|||
D627FF76217E923E00CC0648 /* DraftsManager.swift in Sources */,
|
||||
D64F80E2215875CC00BEF393 /* XCBActionType.swift in Sources */,
|
||||
04586B4322B301470021BD04 /* AppearancePrefsView.swift in Sources */,
|
||||
D6FF9860255C717400845181 /* AccountSwitchingContainerViewController.swift in Sources */,
|
||||
D670F8B62537DC890046588A /* EmojiPickerWrapper.swift in Sources */,
|
||||
D67C57AF21E28EAD00C3118B /* Array+Uniques.swift in Sources */,
|
||||
D6945C3223AC4D36005C403C /* HashtagTimelineViewController.swift in Sources */,
|
||||
|
|
|
@ -130,50 +130,64 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||
func showAppOrOnboardingUI(session: UISceneSession? = nil) {
|
||||
let session = session ?? window!.windowScene!.session
|
||||
if LocalData.shared.onboardingComplete {
|
||||
if session.mastodonController == nil {
|
||||
let account = LocalData.shared.getMostRecentAccount()!
|
||||
if session.mastodonController == nil {
|
||||
session.mastodonController = MastodonController.getForAccount(account)
|
||||
}
|
||||
|
||||
showAppUI()
|
||||
activateAccount(account, animated: false)
|
||||
} else {
|
||||
showOnboardingUI()
|
||||
window!.rootViewController = createOnboardingUI()
|
||||
}
|
||||
}
|
||||
|
||||
func activateAccount(_ account: LocalData.UserAccountInfo) {
|
||||
func activateAccount(_ account: LocalData.UserAccountInfo, animated: Bool) {
|
||||
let oldIndex = LocalData.shared.accounts.firstIndex(where: { $0.id == LocalData.shared.mostRecentAccountID })!
|
||||
let newIndex = LocalData.shared.accounts.firstIndex(of: account)!
|
||||
|
||||
LocalData.shared.setMostRecentAccount(account)
|
||||
window!.windowScene!.session.mastodonController = MastodonController.getForAccount(account)
|
||||
showAppUI()
|
||||
|
||||
let newRoot = createAppUI()
|
||||
if let container = window?.rootViewController as? AccountSwitchingContainerViewController {
|
||||
let direction: AccountSwitchingContainerViewController.AnimationDirection
|
||||
if animated {
|
||||
direction = newIndex > oldIndex ? .upwards : .downwards
|
||||
} else {
|
||||
direction = .none
|
||||
}
|
||||
container.setRoot(newRoot, animating: direction)
|
||||
} else {
|
||||
window!.rootViewController = AccountSwitchingContainerViewController(root: newRoot)
|
||||
}
|
||||
}
|
||||
|
||||
func logoutCurrent() {
|
||||
LocalData.shared.removeAccount(LocalData.shared.getMostRecentAccount()!)
|
||||
if LocalData.shared.onboardingComplete {
|
||||
activateAccount(LocalData.shared.accounts.first!)
|
||||
activateAccount(LocalData.shared.accounts.first!, animated: false)
|
||||
} else {
|
||||
showOnboardingUI()
|
||||
window!.rootViewController = createOnboardingUI()
|
||||
}
|
||||
}
|
||||
|
||||
func showAppUI() {
|
||||
func createAppUI() -> TuskerRootViewController {
|
||||
let mastodonController = window!.windowScene!.session.mastodonController!
|
||||
mastodonController.getOwnAccount()
|
||||
mastodonController.getOwnInstance()
|
||||
|
||||
let rootController: UIViewController
|
||||
if #available(iOS 14.0, *) {
|
||||
rootController = MainSplitViewController(mastodonController: mastodonController)
|
||||
if #available(iOS 14.0, *),
|
||||
UIDevice.current.userInterfaceIdiom != .phone {
|
||||
return MainSplitViewController(mastodonController: mastodonController)
|
||||
} else {
|
||||
rootController = MainTabBarViewController(mastodonController: mastodonController)
|
||||
return MainTabBarViewController(mastodonController: mastodonController)
|
||||
}
|
||||
window!.rootViewController = rootController
|
||||
}
|
||||
|
||||
func showOnboardingUI() {
|
||||
func createOnboardingUI() -> UIViewController {
|
||||
let onboarding = OnboardingViewController()
|
||||
onboarding.onboardingDelegate = self
|
||||
window!.rootViewController = onboarding
|
||||
return onboarding
|
||||
}
|
||||
|
||||
@objc func themePrefChanged() {
|
||||
|
@ -184,7 +198,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||
|
||||
extension SceneDelegate: OnboardingViewControllerDelegate {
|
||||
func didFinishOnboarding(account: LocalData.UserAccountInfo) {
|
||||
activateAccount(account)
|
||||
activateAccount(account, animated: false)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -86,15 +86,16 @@ class FastAccountSwitcherViewController: UIViewController {
|
|||
}
|
||||
}
|
||||
|
||||
func hide() {
|
||||
func hide(completion: (() -> Void)? = nil) {
|
||||
lastSelectedAccountViewIndex = nil
|
||||
selectionChangedFeedbackGenerator = nil
|
||||
|
||||
UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseInOut) {
|
||||
UIView.animate(withDuration: 0.15, delay: 0, options: .curveEaseInOut) {
|
||||
self.view.alpha = 0
|
||||
} completion: { (_) in
|
||||
self.view.alpha = 1
|
||||
self.view.isHidden = true
|
||||
completion?()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,7 +129,12 @@ class FastAccountSwitcherViewController: UIViewController {
|
|||
selectionChangedFeedbackGenerator?.impactOccurred()
|
||||
}
|
||||
selectionChangedFeedbackGenerator = nil
|
||||
(view.window!.windowScene!.delegate as! SceneDelegate).activateAccount(account)
|
||||
|
||||
hide() {
|
||||
(self.view.window!.windowScene!.delegate as! SceneDelegate).activateAccount(account, animated: true)
|
||||
}
|
||||
} else {
|
||||
hide()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,7 +158,6 @@ class FastAccountSwitcherViewController: UIViewController {
|
|||
let location = recognizer.location(in: view)
|
||||
if let index = lastSelectedAccountViewIndex {
|
||||
switchAccount(newIndex: index)
|
||||
hide()
|
||||
} else if !(delegate?.fastAccountSwitcher(self, triggerZoneContains: location) ?? false) {
|
||||
hide()
|
||||
}
|
||||
|
@ -172,7 +177,6 @@ class FastAccountSwitcherViewController: UIViewController {
|
|||
case .ended:
|
||||
if let index = lastSelectedAccountViewIndex {
|
||||
switchAccount(newIndex: index)
|
||||
hide()
|
||||
}
|
||||
|
||||
default:
|
||||
|
@ -207,10 +211,10 @@ class FastAccountSwitcherViewController: UIViewController {
|
|||
touchBeganFeedbackWorkItem = nil
|
||||
|
||||
switchAccount(newIndex: tappedIndex)
|
||||
}
|
||||
|
||||
} else {
|
||||
hide()
|
||||
}
|
||||
}
|
||||
|
||||
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
if touches.count == 1,
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
//
|
||||
// AccountSwitchingContainerViewController.swift
|
||||
// Tusker
|
||||
//
|
||||
// Created by Shadowfacts on 11/11/20.
|
||||
// Copyright © 2020 Shadowfacts. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class AccountSwitchingContainerViewController: UIViewController {
|
||||
|
||||
private(set) var root: TuskerRootViewController
|
||||
|
||||
init(root: TuskerRootViewController) {
|
||||
self.root = root
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
embedChild(root)
|
||||
}
|
||||
|
||||
func setRoot(_ newRoot: TuskerRootViewController, animating direction: AnimationDirection) {
|
||||
let oldRoot = self.root
|
||||
if direction == .none {
|
||||
oldRoot.removeViewAndController()
|
||||
}
|
||||
self.root = newRoot
|
||||
embedChild(newRoot)
|
||||
|
||||
if direction != .none {
|
||||
if UIAccessibility.prefersCrossFadeTransitionsBackwardsCompat {
|
||||
newRoot.view.alpha = 0
|
||||
|
||||
UIView.animate(withDuration: 0.4, delay: 0, options: .curveEaseInOut) {
|
||||
newRoot.view.alpha = 1
|
||||
oldRoot.view.alpha = 0
|
||||
} completion: { (_) in
|
||||
oldRoot.removeViewAndController()
|
||||
}
|
||||
} else {
|
||||
let sign: CGFloat = direction == .downwards ? -1 : 1
|
||||
let newInitialOffset = sign * view.bounds.height
|
||||
|
||||
newRoot.view.transform = CGAffineTransform(translationX: 0, y: newInitialOffset)
|
||||
|
||||
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseInOut) {
|
||||
newRoot.view.transform = .identity
|
||||
oldRoot.view.transform = CGAffineTransform(translationX: 0, y: -newInitialOffset)
|
||||
} completion: { (_) in
|
||||
oldRoot.removeViewAndController()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension AccountSwitchingContainerViewController {
|
||||
enum AnimationDirection {
|
||||
case none, downwards, upwards
|
||||
}
|
||||
}
|
||||
|
||||
extension AccountSwitchingContainerViewController: TuskerRootViewController {
|
||||
func presentCompose() {
|
||||
root.presentCompose()
|
||||
}
|
||||
|
||||
func select(tab: MainTabBarViewController.Tab) {
|
||||
root.select(tab: tab)
|
||||
}
|
||||
|
||||
func getTabController(tab: MainTabBarViewController.Tab) -> UIViewController? {
|
||||
root.getTabController(tab: tab)
|
||||
}
|
||||
}
|
|
@ -69,7 +69,7 @@ class PreferencesNavigationController: UINavigationController {
|
|||
let account = notification.userInfo!["account"] as! LocalData.UserAccountInfo
|
||||
isSwitchingAccounts = true
|
||||
dismiss(animated: true) { // dismiss preferences
|
||||
sceneDelegate.activateAccount(account)
|
||||
sceneDelegate.activateAccount(account, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ extension PreferencesNavigationController: OnboardingViewControllerDelegate {
|
|||
let sceneDelegate = self.view.window!.windowScene!.delegate as! SceneDelegate
|
||||
self.dismiss(animated: true) { // dismiss instance selector
|
||||
self.dismiss(animated: true) { // dismiss preferences
|
||||
sceneDelegate.activateAccount(account)
|
||||
sceneDelegate.activateAccount(account, animated: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue