Remove redundant main actor dispatch

This commit is contained in:
Marcus Kida 2024-01-04 16:28:22 +01:00
parent 97bfdabe0c
commit f50d48dc4e
No known key found for this signature in database
GPG Key ID: 19FF64E08013CA40
1 changed files with 137 additions and 139 deletions

View File

@ -88,7 +88,7 @@ class MainTabBarController: UITabBarController {
} }
@MainActor @MainActor
func viewController(context: AppContext, authContext: AuthContext?, coordinator: SceneCoordinator) async -> UIViewController { func viewController(context: AppContext, authContext: AuthContext?, coordinator: SceneCoordinator) -> UIViewController {
guard let authContext = authContext else { guard let authContext = authContext else {
return UITableViewController() return UITableViewController()
} }
@ -171,151 +171,149 @@ extension MainTabBarController {
view.backgroundColor = .systemBackground view.backgroundColor = .systemBackground
// seealso: `ThemeService.apply(theme:)` // seealso: `ThemeService.apply(theme:)`
Task { @MainActor in let tabs = Tab.allCases
let tabs = Tab.allCases var viewControllers = [UIViewController]()
var viewControllers = [UIViewController]()
for tab in tabs {
for tab in tabs { let viewController = tab.viewController(context: context, authContext: authContext, coordinator: coordinator)
let viewController = await tab.viewController(context: context, authContext: authContext, coordinator: coordinator) viewController.tabBarItem.tag = tab.tag
viewController.tabBarItem.tag = tab.tag viewController.tabBarItem.title = tab.title // needs for acessiblity large content label
viewController.tabBarItem.title = tab.title // needs for acessiblity large content label viewController.tabBarItem.image = tab.image.imageWithoutBaseline()
viewController.tabBarItem.image = tab.image.imageWithoutBaseline() viewController.tabBarItem.largeContentSizeImage = tab.largeImage.imageWithoutBaseline()
viewController.tabBarItem.largeContentSizeImage = tab.largeImage.imageWithoutBaseline() viewController.tabBarItem.accessibilityLabel = tab.title
viewController.tabBarItem.accessibilityLabel = tab.title viewController.tabBarItem.accessibilityUserInputLabels = tab.inputLabels
viewController.tabBarItem.accessibilityUserInputLabels = tab.inputLabels viewController.tabBarItem.imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0)
viewController.tabBarItem.imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0) viewControllers.append(viewController)
viewControllers.append(viewController) }
_viewControllers = viewControllers
setViewControllers(viewControllers, animated: false)
selectedIndex = 0
// hacky workaround for FB11986255 (Setting accessibilityUserInputLabels on a UITabBarItem has no effect)
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(50)) {
if let searchItem = self.tabBar.subviews.first(where: { $0.accessibilityLabel == Tab.search.title }) {
searchItem.accessibilityUserInputLabels = Tab.search.inputLabels
} }
}
_viewControllers = viewControllers
setViewControllers(viewControllers, animated: false) context.apiService.error
selectedIndex = 0
// hacky workaround for FB11986255 (Setting accessibilityUserInputLabels on a UITabBarItem has no effect)
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(50)) {
if let searchItem = self.tabBar.subviews.first(where: { $0.accessibilityLabel == Tab.search.title }) {
searchItem.accessibilityUserInputLabels = Tab.search.inputLabels
}
}
context.apiService.error
.receive(on: DispatchQueue.main)
.sink { [weak self] error in
guard let self = self, let coordinator = self.coordinator else { return }
switch error {
case .implicit:
break
case .explicit:
let alertController = UIAlertController(for: error, title: nil, preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alertController.addAction(okAction)
_ = coordinator.present(
scene: .alertController(alertController: alertController),
from: nil,
transition: .alertController(animated: true, completion: nil)
)
}
}
.store(in: &disposeBag)
// handle post failure
// handle push notification.
// toggle entry when finish fetch latest notification
Publishers.CombineLatest(
context.notificationService.unreadNotificationCountDidUpdate,
$currentTab
)
.receive(on: DispatchQueue.main) .receive(on: DispatchQueue.main)
.sink { [weak self] authentication, currentTab in .sink { [weak self] error in
guard let self = self else { return } guard let self = self, let coordinator = self.coordinator else { return }
guard let notificationViewController = self.notificationViewController else { return } switch error {
case .implicit:
let authentication = self.authContext?.mastodonAuthenticationBox.userAuthorization break
let hasUnreadPushNotification: Bool = authentication.flatMap { authentication in case .explicit:
let count = UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: authentication.accessToken) let alertController = UIAlertController(for: error, title: nil, preferredStyle: .alert)
return count > 0 let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
} ?? false alertController.addAction(okAction)
_ = coordinator.present(
let image: UIImage scene: .alertController(alertController: alertController),
if hasUnreadPushNotification { from: nil,
let imageConfiguration = UIImage.SymbolConfiguration(paletteColors: [.red, SystemTheme.tabBarItemNormalIconColor]) transition: .alertController(animated: true, completion: nil)
image = UIImage(systemName: "bell.badge", withConfiguration: imageConfiguration)!
} else {
image = Tab.notifications.image
}
notificationViewController.tabBarItem.image = image.imageWithoutBaseline()
notificationViewController.navigationController?.tabBarItem.image = image.imageWithoutBaseline()
}
.store(in: &disposeBag)
layoutAvatarButton()
$avatarURL
.receive(on: DispatchQueue.main)
.sink { [weak self] avatarURL in
guard let self = self else { return }
self.avatarButton.avatarImageView.setImage(
url: avatarURL,
placeholder: .placeholder(color: .systemFill),
scaleToSize: MainTabBarController.avatarButtonSize
) )
} }
.store(in: &disposeBag) }
.store(in: &disposeBag)
NotificationCenter.default.publisher(for: .userFetched)
.receive(on: DispatchQueue.main) // handle post failure
.sink { [weak self] _ in
guard let self = self else { return } // handle push notification.
if let user = self.authContext?.mastodonAuthenticationBox.authentication.user(in: self.context.managedObjectContext) { // toggle entry when finish fetch latest notification
self.avatarURLObserver = user.publisher(for: \.avatar) Publishers.CombineLatest(
.sink { [weak self, weak user] _ in context.notificationService.unreadNotificationCountDidUpdate,
guard let self = self else { return }
guard let user = user else { return }
guard user.managedObjectContext != nil else { return }
self.avatarURL = user.avatarImageURL()
}
// a11y
let _profileTabItem = self.tabBar.items?.first { item in item.tag == Tab.me.tag }
guard let profileTabItem = _profileTabItem else { return }
profileTabItem.accessibilityHint = L10n.Scene.AccountList.tabBarHint(user.displayNameWithFallback)
self.context.authenticationService.updateActiveUserAccountPublisher
.sink { [weak self] in
self?.updateUserAccount()
}
.store(in: &self.disposeBag)
} else {
self.avatarURLObserver = nil
}
}
.store(in: &disposeBag)
let tabBarLongPressGestureRecognizer = UILongPressGestureRecognizer()
tabBarLongPressGestureRecognizer.addTarget(self, action: #selector(MainTabBarController.tabBarLongPressGestureRecognizerHandler(_:)))
tabBarLongPressGestureRecognizer.delegate = self
tabBar.addGestureRecognizer(tabBarLongPressGestureRecognizer)
let tabBarDoubleTapGestureRecognizer = UITapGestureRecognizer()
tabBarDoubleTapGestureRecognizer.numberOfTapsRequired = 2
tabBarDoubleTapGestureRecognizer.addTarget(self, action: #selector(MainTabBarController.tabBarDoubleTapGestureRecognizerHandler(_:)))
tabBarDoubleTapGestureRecognizer.delaysTouchesEnded = false
tabBar.addGestureRecognizer(tabBarDoubleTapGestureRecognizer)
self.isReadyForWizardAvatarButton = authContext != nil
$currentTab $currentTab
.receive(on: DispatchQueue.main) )
.sink { [weak self] tab in .receive(on: DispatchQueue.main)
guard let self = self else { return } .sink { [weak self] authentication, currentTab in
self.updateAvatarButtonAppearance() guard let self = self else { return }
} guard let notificationViewController = self.notificationViewController else { return }
.store(in: &disposeBag)
updateTabBarDisplay() let authentication = self.authContext?.mastodonAuthenticationBox.userAuthorization
let hasUnreadPushNotification: Bool = authentication.flatMap { authentication in
let count = UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: authentication.accessToken)
return count > 0
} ?? false
let image: UIImage
if hasUnreadPushNotification {
let imageConfiguration = UIImage.SymbolConfiguration(paletteColors: [.red, SystemTheme.tabBarItemNormalIconColor])
image = UIImage(systemName: "bell.badge", withConfiguration: imageConfiguration)!
} else {
image = Tab.notifications.image
}
notificationViewController.tabBarItem.image = image.imageWithoutBaseline()
notificationViewController.navigationController?.tabBarItem.image = image.imageWithoutBaseline()
} }
.store(in: &disposeBag)
layoutAvatarButton()
$avatarURL
.receive(on: DispatchQueue.main)
.sink { [weak self] avatarURL in
guard let self = self else { return }
self.avatarButton.avatarImageView.setImage(
url: avatarURL,
placeholder: .placeholder(color: .systemFill),
scaleToSize: MainTabBarController.avatarButtonSize
)
}
.store(in: &disposeBag)
NotificationCenter.default.publisher(for: .userFetched)
.receive(on: DispatchQueue.main)
.sink { [weak self] _ in
guard let self = self else { return }
if let user = self.authContext?.mastodonAuthenticationBox.authentication.user(in: self.context.managedObjectContext) {
self.avatarURLObserver = user.publisher(for: \.avatar)
.sink { [weak self, weak user] _ in
guard let self = self else { return }
guard let user = user else { return }
guard user.managedObjectContext != nil else { return }
self.avatarURL = user.avatarImageURL()
}
// a11y
let _profileTabItem = self.tabBar.items?.first { item in item.tag == Tab.me.tag }
guard let profileTabItem = _profileTabItem else { return }
profileTabItem.accessibilityHint = L10n.Scene.AccountList.tabBarHint(user.displayNameWithFallback)
self.context.authenticationService.updateActiveUserAccountPublisher
.sink { [weak self] in
self?.updateUserAccount()
}
.store(in: &self.disposeBag)
} else {
self.avatarURLObserver = nil
}
}
.store(in: &disposeBag)
let tabBarLongPressGestureRecognizer = UILongPressGestureRecognizer()
tabBarLongPressGestureRecognizer.addTarget(self, action: #selector(MainTabBarController.tabBarLongPressGestureRecognizerHandler(_:)))
tabBarLongPressGestureRecognizer.delegate = self
tabBar.addGestureRecognizer(tabBarLongPressGestureRecognizer)
let tabBarDoubleTapGestureRecognizer = UITapGestureRecognizer()
tabBarDoubleTapGestureRecognizer.numberOfTapsRequired = 2
tabBarDoubleTapGestureRecognizer.addTarget(self, action: #selector(MainTabBarController.tabBarDoubleTapGestureRecognizerHandler(_:)))
tabBarDoubleTapGestureRecognizer.delaysTouchesEnded = false
tabBar.addGestureRecognizer(tabBarDoubleTapGestureRecognizer)
self.isReadyForWizardAvatarButton = authContext != nil
$currentTab
.receive(on: DispatchQueue.main)
.sink { [weak self] tab in
guard let self = self else { return }
self.updateAvatarButtonAppearance()
}
.store(in: &disposeBag)
updateTabBarDisplay()
} }
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {