Add account switching animation
This commit is contained in:
parent
904ff4eecf
commit
75d26e613b
|
@ -76,7 +76,6 @@ public class Client {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard let result = try? Client.decoder.decode(Result.self, from: data) else {
|
guard let result = try? Client.decoder.decode(Result.self, from: data) else {
|
||||||
print(request)
|
|
||||||
completion(.failure(.invalidModel))
|
completion(.failure(.invalidModel))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -297,6 +297,7 @@
|
||||||
D6F2E966249E8BFD005846BB /* CrashReporterViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6F2E964249E8BFD005846BB /* CrashReporterViewController.xib */; };
|
D6F2E966249E8BFD005846BB /* CrashReporterViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6F2E964249E8BFD005846BB /* CrashReporterViewController.xib */; };
|
||||||
D6F953EC212519E700CF0F2B /* TimelineTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F953EB212519E700CF0F2B /* TimelineTableViewController.swift */; };
|
D6F953EC212519E700CF0F2B /* TimelineTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F953EB212519E700CF0F2B /* TimelineTableViewController.swift */; };
|
||||||
D6F953F021251A2900CF0F2B /* MastodonController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F953EF21251A2900CF0F2B /* MastodonController.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 */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
@ -649,6 +650,7 @@
|
||||||
D6F2E964249E8BFD005846BB /* CrashReporterViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CrashReporterViewController.xib; sourceTree = "<group>"; };
|
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>"; };
|
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>"; };
|
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 */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
@ -975,6 +977,7 @@
|
||||||
D641C782213DD7F0004B4513 /* Main */ = {
|
D641C782213DD7F0004B4513 /* Main */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
D6FF985F255C717400845181 /* AccountSwitchingContainerViewController.swift */,
|
||||||
D6F0B12A24A3071C001E48C3 /* MainSplitViewController.swift */,
|
D6F0B12A24A3071C001E48C3 /* MainSplitViewController.swift */,
|
||||||
04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */,
|
04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */,
|
||||||
D6F0B17424A3A1AA001E48C3 /* MainSidebarViewController.swift */,
|
D6F0B17424A3A1AA001E48C3 /* MainSidebarViewController.swift */,
|
||||||
|
@ -1971,6 +1974,7 @@
|
||||||
D627FF76217E923E00CC0648 /* DraftsManager.swift in Sources */,
|
D627FF76217E923E00CC0648 /* DraftsManager.swift in Sources */,
|
||||||
D64F80E2215875CC00BEF393 /* XCBActionType.swift in Sources */,
|
D64F80E2215875CC00BEF393 /* XCBActionType.swift in Sources */,
|
||||||
04586B4322B301470021BD04 /* AppearancePrefsView.swift in Sources */,
|
04586B4322B301470021BD04 /* AppearancePrefsView.swift in Sources */,
|
||||||
|
D6FF9860255C717400845181 /* AccountSwitchingContainerViewController.swift in Sources */,
|
||||||
D670F8B62537DC890046588A /* EmojiPickerWrapper.swift in Sources */,
|
D670F8B62537DC890046588A /* EmojiPickerWrapper.swift in Sources */,
|
||||||
D67C57AF21E28EAD00C3118B /* Array+Uniques.swift in Sources */,
|
D67C57AF21E28EAD00C3118B /* Array+Uniques.swift in Sources */,
|
||||||
D6945C3223AC4D36005C403C /* HashtagTimelineViewController.swift in Sources */,
|
D6945C3223AC4D36005C403C /* HashtagTimelineViewController.swift in Sources */,
|
||||||
|
|
|
@ -130,50 +130,64 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||||
func showAppOrOnboardingUI(session: UISceneSession? = nil) {
|
func showAppOrOnboardingUI(session: UISceneSession? = nil) {
|
||||||
let session = session ?? window!.windowScene!.session
|
let session = session ?? window!.windowScene!.session
|
||||||
if LocalData.shared.onboardingComplete {
|
if LocalData.shared.onboardingComplete {
|
||||||
|
let account = LocalData.shared.getMostRecentAccount()!
|
||||||
if session.mastodonController == nil {
|
if session.mastodonController == nil {
|
||||||
let account = LocalData.shared.getMostRecentAccount()!
|
|
||||||
session.mastodonController = MastodonController.getForAccount(account)
|
session.mastodonController = MastodonController.getForAccount(account)
|
||||||
}
|
}
|
||||||
|
|
||||||
showAppUI()
|
activateAccount(account, animated: false)
|
||||||
} else {
|
} 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)
|
LocalData.shared.setMostRecentAccount(account)
|
||||||
window!.windowScene!.session.mastodonController = MastodonController.getForAccount(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() {
|
func logoutCurrent() {
|
||||||
LocalData.shared.removeAccount(LocalData.shared.getMostRecentAccount()!)
|
LocalData.shared.removeAccount(LocalData.shared.getMostRecentAccount()!)
|
||||||
if LocalData.shared.onboardingComplete {
|
if LocalData.shared.onboardingComplete {
|
||||||
activateAccount(LocalData.shared.accounts.first!)
|
activateAccount(LocalData.shared.accounts.first!, animated: false)
|
||||||
} else {
|
} else {
|
||||||
showOnboardingUI()
|
window!.rootViewController = createOnboardingUI()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func showAppUI() {
|
func createAppUI() -> TuskerRootViewController {
|
||||||
let mastodonController = window!.windowScene!.session.mastodonController!
|
let mastodonController = window!.windowScene!.session.mastodonController!
|
||||||
mastodonController.getOwnAccount()
|
mastodonController.getOwnAccount()
|
||||||
mastodonController.getOwnInstance()
|
mastodonController.getOwnInstance()
|
||||||
|
|
||||||
let rootController: UIViewController
|
if #available(iOS 14.0, *),
|
||||||
if #available(iOS 14.0, *) {
|
UIDevice.current.userInterfaceIdiom != .phone {
|
||||||
rootController = MainSplitViewController(mastodonController: mastodonController)
|
return MainSplitViewController(mastodonController: mastodonController)
|
||||||
} else {
|
} else {
|
||||||
rootController = MainTabBarViewController(mastodonController: mastodonController)
|
return MainTabBarViewController(mastodonController: mastodonController)
|
||||||
}
|
}
|
||||||
window!.rootViewController = rootController
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func showOnboardingUI() {
|
func createOnboardingUI() -> UIViewController {
|
||||||
let onboarding = OnboardingViewController()
|
let onboarding = OnboardingViewController()
|
||||||
onboarding.onboardingDelegate = self
|
onboarding.onboardingDelegate = self
|
||||||
window!.rootViewController = onboarding
|
return onboarding
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func themePrefChanged() {
|
@objc func themePrefChanged() {
|
||||||
|
@ -184,7 +198,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||||
|
|
||||||
extension SceneDelegate: OnboardingViewControllerDelegate {
|
extension SceneDelegate: OnboardingViewControllerDelegate {
|
||||||
func didFinishOnboarding(account: LocalData.UserAccountInfo) {
|
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
|
lastSelectedAccountViewIndex = nil
|
||||||
selectionChangedFeedbackGenerator = 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
|
self.view.alpha = 0
|
||||||
} completion: { (_) in
|
} completion: { (_) in
|
||||||
self.view.alpha = 1
|
self.view.alpha = 1
|
||||||
self.view.isHidden = true
|
self.view.isHidden = true
|
||||||
|
completion?()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +129,12 @@ class FastAccountSwitcherViewController: UIViewController {
|
||||||
selectionChangedFeedbackGenerator?.impactOccurred()
|
selectionChangedFeedbackGenerator?.impactOccurred()
|
||||||
}
|
}
|
||||||
selectionChangedFeedbackGenerator = nil
|
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)
|
let location = recognizer.location(in: view)
|
||||||
if let index = lastSelectedAccountViewIndex {
|
if let index = lastSelectedAccountViewIndex {
|
||||||
switchAccount(newIndex: index)
|
switchAccount(newIndex: index)
|
||||||
hide()
|
|
||||||
} else if !(delegate?.fastAccountSwitcher(self, triggerZoneContains: location) ?? false) {
|
} else if !(delegate?.fastAccountSwitcher(self, triggerZoneContains: location) ?? false) {
|
||||||
hide()
|
hide()
|
||||||
}
|
}
|
||||||
|
@ -172,7 +177,6 @@ class FastAccountSwitcherViewController: UIViewController {
|
||||||
case .ended:
|
case .ended:
|
||||||
if let index = lastSelectedAccountViewIndex {
|
if let index = lastSelectedAccountViewIndex {
|
||||||
switchAccount(newIndex: index)
|
switchAccount(newIndex: index)
|
||||||
hide()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -207,9 +211,9 @@ class FastAccountSwitcherViewController: UIViewController {
|
||||||
touchBeganFeedbackWorkItem = nil
|
touchBeganFeedbackWorkItem = nil
|
||||||
|
|
||||||
switchAccount(newIndex: tappedIndex)
|
switchAccount(newIndex: tappedIndex)
|
||||||
|
} else {
|
||||||
|
hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
hide()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||||
|
|
|
@ -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
|
let account = notification.userInfo!["account"] as! LocalData.UserAccountInfo
|
||||||
isSwitchingAccounts = true
|
isSwitchingAccounts = true
|
||||||
dismiss(animated: true) { // dismiss preferences
|
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
|
let sceneDelegate = self.view.window!.windowScene!.delegate as! SceneDelegate
|
||||||
self.dismiss(animated: true) { // dismiss instance selector
|
self.dismiss(animated: true) { // dismiss instance selector
|
||||||
self.dismiss(animated: true) { // dismiss preferences
|
self.dismiss(animated: true) { // dismiss preferences
|
||||||
sceneDelegate.activateAccount(account)
|
sceneDelegate.activateAccount(account, animated: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue