Merge pull request #617 from mastodon/account_toggle_double_tap_ipad

feat: Implement double-tap account switching on iPad
This commit is contained in:
Marcus Kida 2022-11-17 16:51:26 +01:00 committed by GitHub
commit 0b0252fca2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 88 additions and 24 deletions

View File

@ -23,6 +23,7 @@
0FB3D33825E6401400AAD544 /* PickServerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB3D33725E6401400AAD544 /* PickServerCell.swift */; };
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 */; };
2A82294F29262EE000D2A1F7 /* AppContext+NextAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A82294E29262EE000D2A1F7 /* AppContext+NextAccount.swift */; };
2D198643261BF09500F0B013 /* SearchResultItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D198642261BF09500F0B013 /* SearchResultItem.swift */; };
2D198649261C0B8500F0B013 /* SearchResultSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D198648261C0B8500F0B013 /* SearchResultSection.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>"; };
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>"; };
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>"; };
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>"; };
@ -2222,6 +2224,7 @@
isa = PBXGroup;
children = (
2DF123A625C3B0210020F248 /* ActiveLabel.swift */,
2A82294E29262EE000D2A1F7 /* AppContext+NextAccount.swift */,
5DF1056325F887CB00D6C0D4 /* AVPlayer.swift */,
2D206B8525F5FB0900143C56 /* Double.swift */,
DBB3BA2926A81C020004F2D4 /* FLAnimatedImageView.swift */,
@ -3465,6 +3468,7 @@
DBFEEC99279BDCDE004F81DD /* ProfileAboutViewModel.swift in Sources */,
2D198649261C0B8500F0B013 /* SearchResultSection.swift in Sources */,
DB4F097B26A039FF00D62E92 /* SearchHistorySection.swift in Sources */,
2A82294F29262EE000D2A1F7 /* AppContext+NextAccount.swift in Sources */,
DBB525302611EBF3002F1F29 /* ProfilePagingViewModel.swift in Sources */,
DB9F58EC26EF435000E7BBE9 /* AccountViewController.swift in Sources */,
2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */,

View 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]
}
}

View File

@ -124,4 +124,17 @@ extension ContentSplitViewController: SidebarViewControllerDelegate {
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()
}
}
}

View File

@ -407,30 +407,7 @@ extension MainTabBarController {
guard let authContext = authContext else { return }
assert(Thread.isMainThread)
let request = MastodonAuthentication.sortedFetchRequest
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]
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)

View File

@ -15,6 +15,7 @@ import MastodonUI
protocol SidebarViewControllerDelegate: AnyObject {
func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab)
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 {
@ -143,6 +144,14 @@ extension SidebarViewController {
let sidebarLongPressGestureRecognizer = UILongPressGestureRecognizer()
sidebarLongPressGestureRecognizer.addTarget(self, action: #selector(SidebarViewController.sidebarLongPressGestureRecognizerHandler(_:)))
collectionView.addGestureRecognizer(sidebarLongPressGestureRecognizer)
let sidebarDoubleTapGestureRecognizer = UITapGestureRecognizer()
sidebarDoubleTapGestureRecognizer.numberOfTapsRequired = 2
sidebarDoubleTapGestureRecognizer.addTarget(self, action: #selector(SidebarViewController.sidebarDoubleTapGestureRecognizerHandler(_:)))
sidebarDoubleTapGestureRecognizer.delaysTouchesEnded = false
sidebarDoubleTapGestureRecognizer.cancelsTouchesInView = true
collectionView.addGestureRecognizer(sidebarDoubleTapGestureRecognizer)
}
private func setupBackground(theme: Theme) {
@ -176,6 +185,20 @@ extension SidebarViewController {
guard let cell = collectionView.cellForItem(at: indexPath) else { return }
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)
}
}