feat: Implement double-tap account switching on iPad
This commit is contained in:
parent
cf28286d89
commit
60d9d3537d
@ -23,6 +23,7 @@
|
|||||||
0FB3D33825E6401400AAD544 /* PickServerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB3D33725E6401400AAD544 /* PickServerCell.swift */; };
|
0FB3D33825E6401400AAD544 /* PickServerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB3D33725E6401400AAD544 /* PickServerCell.swift */; };
|
||||||
164F0EBC267D4FE400249499 /* BoopSound.caf in Resources */ = {isa = PBXBuildFile; fileRef = 164F0EBB267D4FE400249499 /* BoopSound.caf */; };
|
164F0EBC267D4FE400249499 /* BoopSound.caf in Resources */ = {isa = PBXBuildFile; fileRef = 164F0EBB267D4FE400249499 /* BoopSound.caf */; };
|
||||||
18BC7629F65E6DB12CB8416D /* Pods_Mastodon_MastodonUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */; };
|
18BC7629F65E6DB12CB8416D /* Pods_Mastodon_MastodonUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */; };
|
||||||
|
2A82294F29262EE000D2A1F7 /* AppContext+NextAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A82294E29262EE000D2A1F7 /* AppContext+NextAccount.swift */; };
|
||||||
2D198643261BF09500F0B013 /* SearchResultItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D198642261BF09500F0B013 /* SearchResultItem.swift */; };
|
2D198643261BF09500F0B013 /* SearchResultItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D198642261BF09500F0B013 /* SearchResultItem.swift */; };
|
||||||
2D198649261C0B8500F0B013 /* SearchResultSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D198648261C0B8500F0B013 /* SearchResultSection.swift */; };
|
2D198649261C0B8500F0B013 /* SearchResultSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D198648261C0B8500F0B013 /* SearchResultSection.swift */; };
|
||||||
2D206B8625F5FB0900143C56 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D206B8525F5FB0900143C56 /* Double.swift */; };
|
2D206B8625F5FB0900143C56 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D206B8525F5FB0900143C56 /* Double.swift */; };
|
||||||
@ -518,6 +519,7 @@
|
|||||||
0FB3D33725E6401400AAD544 /* PickServerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerCell.swift; sourceTree = "<group>"; };
|
0FB3D33725E6401400AAD544 /* PickServerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerCell.swift; sourceTree = "<group>"; };
|
||||||
164F0EBB267D4FE400249499 /* BoopSound.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = BoopSound.caf; sourceTree = "<group>"; };
|
164F0EBB267D4FE400249499 /* BoopSound.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = BoopSound.caf; sourceTree = "<group>"; };
|
||||||
1D6D967E77A5357E2C6110D9 /* Pods-Mastodon.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.asdk - debug.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.asdk - debug.xcconfig"; sourceTree = "<group>"; };
|
1D6D967E77A5357E2C6110D9 /* Pods-Mastodon.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.asdk - debug.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.asdk - debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
2A82294E29262EE000D2A1F7 /* AppContext+NextAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppContext+NextAccount.swift"; sourceTree = "<group>"; };
|
||||||
2D198642261BF09500F0B013 /* SearchResultItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultItem.swift; sourceTree = "<group>"; };
|
2D198642261BF09500F0B013 /* SearchResultItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultItem.swift; sourceTree = "<group>"; };
|
||||||
2D198648261C0B8500F0B013 /* SearchResultSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultSection.swift; sourceTree = "<group>"; };
|
2D198648261C0B8500F0B013 /* SearchResultSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultSection.swift; sourceTree = "<group>"; };
|
||||||
2D206B8525F5FB0900143C56 /* Double.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = "<group>"; };
|
2D206B8525F5FB0900143C56 /* Double.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = "<group>"; };
|
||||||
@ -2222,6 +2224,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
2DF123A625C3B0210020F248 /* ActiveLabel.swift */,
|
2DF123A625C3B0210020F248 /* ActiveLabel.swift */,
|
||||||
|
2A82294E29262EE000D2A1F7 /* AppContext+NextAccount.swift */,
|
||||||
5DF1056325F887CB00D6C0D4 /* AVPlayer.swift */,
|
5DF1056325F887CB00D6C0D4 /* AVPlayer.swift */,
|
||||||
2D206B8525F5FB0900143C56 /* Double.swift */,
|
2D206B8525F5FB0900143C56 /* Double.swift */,
|
||||||
DBB3BA2926A81C020004F2D4 /* FLAnimatedImageView.swift */,
|
DBB3BA2926A81C020004F2D4 /* FLAnimatedImageView.swift */,
|
||||||
@ -3465,6 +3468,7 @@
|
|||||||
DBFEEC99279BDCDE004F81DD /* ProfileAboutViewModel.swift in Sources */,
|
DBFEEC99279BDCDE004F81DD /* ProfileAboutViewModel.swift in Sources */,
|
||||||
2D198649261C0B8500F0B013 /* SearchResultSection.swift in Sources */,
|
2D198649261C0B8500F0B013 /* SearchResultSection.swift in Sources */,
|
||||||
DB4F097B26A039FF00D62E92 /* SearchHistorySection.swift in Sources */,
|
DB4F097B26A039FF00D62E92 /* SearchHistorySection.swift in Sources */,
|
||||||
|
2A82294F29262EE000D2A1F7 /* AppContext+NextAccount.swift in Sources */,
|
||||||
DBB525302611EBF3002F1F29 /* ProfilePagingViewModel.swift in Sources */,
|
DBB525302611EBF3002F1F29 /* ProfilePagingViewModel.swift in Sources */,
|
||||||
DB9F58EC26EF435000E7BBE9 /* AccountViewController.swift in Sources */,
|
DB9F58EC26EF435000E7BBE9 /* AccountViewController.swift in Sources */,
|
||||||
2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */,
|
2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */,
|
||||||
|
47
Mastodon/Extension/AppContext+NextAccount.swift
Normal file
47
Mastodon/Extension/AppContext+NextAccount.swift
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
//
|
||||||
|
// AppContext+NextAccount.swift
|
||||||
|
// Mastodon
|
||||||
|
//
|
||||||
|
// Created by Marcus Kida on 17.11.22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import CoreData
|
||||||
|
import CoreDataStack
|
||||||
|
import MastodonCore
|
||||||
|
import MastodonSDK
|
||||||
|
|
||||||
|
extension AppContext {
|
||||||
|
func nextAccount(in authContext: AuthContext) -> MastodonAuthentication? {
|
||||||
|
let request = MastodonAuthentication.sortedFetchRequest
|
||||||
|
guard
|
||||||
|
let accounts = try? managedObjectContext.fetch(request),
|
||||||
|
accounts.count > 1
|
||||||
|
else { return nil }
|
||||||
|
|
||||||
|
let nextSelectedAccountIndex: Int? = {
|
||||||
|
for (index, account) in accounts.enumerated() {
|
||||||
|
guard account == authContext.mastodonAuthenticationBox
|
||||||
|
.authenticationRecord
|
||||||
|
.object(in: managedObjectContext)
|
||||||
|
else { continue }
|
||||||
|
|
||||||
|
let nextAccountIndex = index + 1
|
||||||
|
|
||||||
|
if accounts.count > nextAccountIndex {
|
||||||
|
return nextAccountIndex
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}()
|
||||||
|
|
||||||
|
guard
|
||||||
|
let nextSelectedAccountIndex = nextSelectedAccountIndex,
|
||||||
|
accounts.count > nextSelectedAccountIndex
|
||||||
|
else { return nil }
|
||||||
|
|
||||||
|
return accounts[nextSelectedAccountIndex]
|
||||||
|
}
|
||||||
|
}
|
@ -124,4 +124,17 @@ extension ContentSplitViewController: SidebarViewControllerDelegate {
|
|||||||
accountListViewController.preferredContentSize = CGSize(width: 375, height: 400)
|
accountListViewController.preferredContentSize = CGSize(width: 375, height: 400)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sidebarViewController(_ sidebarViewController: SidebarViewController, didDoubleTapItem item: SidebarViewModel.Item, sourceView: UIView) {
|
||||||
|
guard case let .tab(tab) = item, tab == .me else { return }
|
||||||
|
guard let authContext = authContext else { return }
|
||||||
|
assert(Thread.isMainThread)
|
||||||
|
|
||||||
|
guard let nextAccount = context.nextAccount(in: authContext) else { return }
|
||||||
|
|
||||||
|
Task { @MainActor in
|
||||||
|
let isActive = try await context.authenticationService.activeMastodonUser(domain: nextAccount.domain, userID: nextAccount.userID)
|
||||||
|
guard isActive else { return }
|
||||||
|
self.coordinator.setup()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -406,30 +406,7 @@ extension MainTabBarController {
|
|||||||
guard let authContext = authContext else { return }
|
guard let authContext = authContext else { return }
|
||||||
assert(Thread.isMainThread)
|
assert(Thread.isMainThread)
|
||||||
|
|
||||||
let request = MastodonAuthentication.sortedFetchRequest
|
guard let nextAccount = context.nextAccount(in: authContext) else { return }
|
||||||
guard let accounts = try? context.managedObjectContext.fetch(request), accounts.count > 1 else { return }
|
|
||||||
|
|
||||||
let nextSelectedAccountIndex: Int? = {
|
|
||||||
for (index, account) in accounts.enumerated() {
|
|
||||||
guard account == authContext.mastodonAuthenticationBox
|
|
||||||
.authenticationRecord
|
|
||||||
.object(in: context.managedObjectContext)
|
|
||||||
else { continue }
|
|
||||||
|
|
||||||
let nextAccountIndex = index + 1
|
|
||||||
|
|
||||||
if accounts.count > nextAccountIndex {
|
|
||||||
return nextAccountIndex
|
|
||||||
} else {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}()
|
|
||||||
|
|
||||||
guard let nextSelectedAccountIndex = nextSelectedAccountIndex, accounts.count > nextSelectedAccountIndex else { return }
|
|
||||||
let nextAccount = accounts[nextSelectedAccountIndex]
|
|
||||||
|
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
let isActive = try await context.authenticationService.activeMastodonUser(domain: nextAccount.domain, userID: nextAccount.userID)
|
let isActive = try await context.authenticationService.activeMastodonUser(domain: nextAccount.domain, userID: nextAccount.userID)
|
||||||
|
@ -15,6 +15,7 @@ import MastodonUI
|
|||||||
protocol SidebarViewControllerDelegate: AnyObject {
|
protocol SidebarViewControllerDelegate: AnyObject {
|
||||||
func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab)
|
func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab)
|
||||||
func sidebarViewController(_ sidebarViewController: SidebarViewController, didLongPressItem item: SidebarViewModel.Item, sourceView: UIView)
|
func sidebarViewController(_ sidebarViewController: SidebarViewController, didLongPressItem item: SidebarViewModel.Item, sourceView: UIView)
|
||||||
|
func sidebarViewController(_ sidebarViewController: SidebarViewController, didDoubleTapItem item: SidebarViewModel.Item, sourceView: UIView)
|
||||||
}
|
}
|
||||||
|
|
||||||
final class SidebarViewController: UIViewController, NeedsDependency {
|
final class SidebarViewController: UIViewController, NeedsDependency {
|
||||||
@ -143,6 +144,14 @@ extension SidebarViewController {
|
|||||||
let sidebarLongPressGestureRecognizer = UILongPressGestureRecognizer()
|
let sidebarLongPressGestureRecognizer = UILongPressGestureRecognizer()
|
||||||
sidebarLongPressGestureRecognizer.addTarget(self, action: #selector(SidebarViewController.sidebarLongPressGestureRecognizerHandler(_:)))
|
sidebarLongPressGestureRecognizer.addTarget(self, action: #selector(SidebarViewController.sidebarLongPressGestureRecognizerHandler(_:)))
|
||||||
collectionView.addGestureRecognizer(sidebarLongPressGestureRecognizer)
|
collectionView.addGestureRecognizer(sidebarLongPressGestureRecognizer)
|
||||||
|
|
||||||
|
let sidebarDoubleTapGestureRecognizer = UITapGestureRecognizer()
|
||||||
|
sidebarDoubleTapGestureRecognizer.numberOfTapsRequired = 2
|
||||||
|
sidebarDoubleTapGestureRecognizer.addTarget(self, action: #selector(SidebarViewController.sidebarDoubleTapGestureRecognizerHandler(_:)))
|
||||||
|
sidebarDoubleTapGestureRecognizer.delaysTouchesBegan = true
|
||||||
|
sidebarDoubleTapGestureRecognizer.cancelsTouchesInView = true
|
||||||
|
collectionView.addGestureRecognizer(sidebarDoubleTapGestureRecognizer)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setupBackground(theme: Theme) {
|
private func setupBackground(theme: Theme) {
|
||||||
@ -177,6 +186,20 @@ extension SidebarViewController {
|
|||||||
delegate?.sidebarViewController(self, didLongPressItem: item, sourceView: cell)
|
delegate?.sidebarViewController(self, didLongPressItem: item, sourceView: cell)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func sidebarDoubleTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) {
|
||||||
|
guard sender.state == .ended else { return }
|
||||||
|
|
||||||
|
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
|
||||||
|
assert(sender.view === collectionView)
|
||||||
|
|
||||||
|
let position = sender.location(in: collectionView)
|
||||||
|
guard let indexPath = collectionView.indexPathForItem(at: position) else { return }
|
||||||
|
guard let diffableDataSource = viewModel.diffableDataSource else { return }
|
||||||
|
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
|
||||||
|
guard let cell = collectionView.cellForItem(at: indexPath) else { return }
|
||||||
|
delegate?.sidebarViewController(self, didDoubleTapItem: item, sourceView: cell)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - UICollectionViewDelegate
|
// MARK: - UICollectionViewDelegate
|
||||||
|
Loading…
x
Reference in New Issue
Block a user