Show avatar in tab/side bar when using new API
This commit is contained in:
parent
cb32c66a59
commit
7c7af945e4
|
@ -11,14 +11,14 @@ import UserAccounts
|
|||
|
||||
class MainSidebarMyProfileCollectionViewCell: UICollectionViewListCell {
|
||||
|
||||
private var verticalImageInset: CGFloat {
|
||||
static var verticalImageInset: CGFloat {
|
||||
if UIDevice.current.userInterfaceIdiom == .mac {
|
||||
return (28 - avatarImageSize) / 2
|
||||
} else {
|
||||
return (44 - avatarImageSize) / 2
|
||||
}
|
||||
}
|
||||
private var avatarImageSize: CGFloat {
|
||||
static var avatarImageSize: CGFloat {
|
||||
if UIDevice.current.userInterfaceIdiom == .mac {
|
||||
return 20
|
||||
} else {
|
||||
|
@ -72,11 +72,11 @@ class MainSidebarMyProfileCollectionViewCell: UICollectionViewListCell {
|
|||
return
|
||||
}
|
||||
config.image = image
|
||||
config.directionalLayoutMargins.top = self.verticalImageInset
|
||||
config.directionalLayoutMargins.bottom = self.verticalImageInset
|
||||
config.imageProperties.maximumSize = CGSize(width: self.avatarImageSize, height: self.avatarImageSize)
|
||||
config.directionalLayoutMargins.top = MainSidebarMyProfileCollectionViewCell.verticalImageInset
|
||||
config.directionalLayoutMargins.bottom = MainSidebarMyProfileCollectionViewCell.verticalImageInset
|
||||
config.imageProperties.maximumSize = CGSize(width: MainSidebarMyProfileCollectionViewCell.avatarImageSize, height: MainSidebarMyProfileCollectionViewCell.avatarImageSize)
|
||||
config.imageProperties.reservedLayoutSize = CGSize(width: UIListContentConfiguration.ImageProperties.standardDimension, height: 0)
|
||||
config.imageProperties.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * self.avatarImageSize
|
||||
config.imageProperties.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * MainSidebarMyProfileCollectionViewCell.avatarImageSize
|
||||
self.contentConfiguration = config
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ class MainSidebarMyProfileCollectionViewCell: UICollectionViewListCell {
|
|||
guard var config = self.contentConfiguration as? UIListContentConfiguration else {
|
||||
return
|
||||
}
|
||||
config.imageProperties.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * avatarImageSize
|
||||
config.imageProperties.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * MainSidebarMyProfileCollectionViewCell.avatarImageSize
|
||||
self.contentConfiguration = config
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import UIKit
|
||||
import Combine
|
||||
import Pachyderm
|
||||
import TuskerPreferences
|
||||
|
||||
@available(iOS 18.0, *)
|
||||
class NewMainTabBarViewController: BaseMainTabBarViewController {
|
||||
|
@ -52,7 +53,7 @@ class NewMainTabBarViewController: BaseMainTabBarViewController {
|
|||
bookmarksTab.preferredPlacement = .optional
|
||||
favoritesTab = UITab(title: "Favorites", image: UIImage(systemName: "star"), identifier: Tab.favorites.rawValue, viewControllerProvider: viewControllerProvider)
|
||||
favoritesTab.preferredPlacement = .optional
|
||||
myProfileTab = UITab(title: "My Profile", image: UIImage(systemName: "person"), identifier: Tab.myProfile.rawValue, viewControllerProvider: viewControllerProvider)
|
||||
myProfileTab = MyProfileTab(mastodonController: mastodonController, viewControllerProvider: viewControllerProvider)
|
||||
|
||||
listsGroup = UITabGroup(title: "Lists", image: nil, identifier: Tab.lists.rawValue, children: []) { _ in
|
||||
// this closure is necessary to prevent UIKit from crashing (FB14860961)
|
||||
|
@ -362,6 +363,13 @@ extension NewMainTabBarViewController: UITabBarControllerDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
private var fastAccountSwitcherIndicator: UIView = {
|
||||
let indicator = FastAccountSwitcherIndicatorView()
|
||||
// need to explicitly set the frame to get it vertically centered
|
||||
indicator.frame = CGRect(origin: .zero, size: indicator.intrinsicContentSize)
|
||||
return indicator
|
||||
}()
|
||||
|
||||
@available(iOS 18.0, *)
|
||||
extension NewMainTabBarViewController: UITabBarController.Sidebar.Delegate {
|
||||
func tabBarController(_ tabBarController: UITabBarController, sidebarVisibilityWillChange sidebar: UITabBarController.Sidebar, animator: any UITabBarController.Sidebar.Animating) {
|
||||
|
@ -375,16 +383,22 @@ extension NewMainTabBarViewController: UITabBarController.Sidebar.Delegate {
|
|||
func tabBarController(_ tabBarController: UITabBarController, sidebar: UITabBarController.Sidebar, itemFor request: UITabSidebarItem.Request) -> UITabSidebarItem {
|
||||
let item = UITabSidebarItem(request: request)
|
||||
if case .tab(let tab) = request.content,
|
||||
UIDevice.current.userInterfaceIdiom != .mac,
|
||||
tab.identifier == Tab.myProfile.rawValue {
|
||||
let indicator = FastAccountSwitcherIndicatorView()
|
||||
// need to explicitly set the frame to get it vertically centered
|
||||
indicator.frame = CGRect(origin: .zero, size: indicator.intrinsicContentSize)
|
||||
item.accessories = [
|
||||
.customView(configuration: .init(customView: indicator, placement: .trailing()))
|
||||
]
|
||||
item.contentConfiguration = MyProfileContentConfiguration(wrapped: item.contentConfiguration, view: $myProfileCell) { [unowned self] in
|
||||
$0.addGestureRecognizer(self.fastAccountSwitcher.createSwitcherGesture())
|
||||
tab.identifier == Tab.myProfile.rawValue,
|
||||
var config = item.contentConfiguration as? UIListContentConfiguration {
|
||||
config.directionalLayoutMargins.top = MainSidebarMyProfileCollectionViewCell.verticalImageInset
|
||||
config.directionalLayoutMargins.bottom = MainSidebarMyProfileCollectionViewCell.verticalImageInset
|
||||
config.imageProperties.maximumSize = CGSize(width: MainSidebarMyProfileCollectionViewCell.avatarImageSize, height: MainSidebarMyProfileCollectionViewCell.avatarImageSize)
|
||||
config.imageProperties.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * MainSidebarMyProfileCollectionViewCell.avatarImageSize
|
||||
|
||||
if UIDevice.current.userInterfaceIdiom != .mac {
|
||||
item.accessories = [
|
||||
.customView(configuration: .init(customView: fastAccountSwitcherIndicator, placement: .trailing()))
|
||||
]
|
||||
item.contentConfiguration = MyProfileContentConfiguration(wrapped: config, view: $myProfileCell) { [unowned self] in
|
||||
$0.addGestureRecognizer(self.fastAccountSwitcher.createSwitcherGesture())
|
||||
}
|
||||
} else {
|
||||
item.contentConfiguration = config
|
||||
}
|
||||
}
|
||||
return item
|
||||
|
@ -502,3 +516,70 @@ private struct MyProfileContentConfiguration: UIContentConfiguration {
|
|||
return .init(wrapped: wrapped.updated(for: state), view: $view, configureView: configureView)
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 18.0, *)
|
||||
private class MyProfileTab: UITab {
|
||||
private let mastodonController: MastodonController
|
||||
private var avatarStyle: AvatarStyle?
|
||||
|
||||
init(mastodonController: MastodonController, viewControllerProvider: @escaping (UITab) -> UIViewController) {
|
||||
self.mastodonController = mastodonController
|
||||
|
||||
// try to add the avatar image synchronously if possible
|
||||
var avatarImage: UIImage?
|
||||
if !Preferences.shared.grayscaleImages,
|
||||
let account = mastodonController.account,
|
||||
let avatarURL = account.avatar,
|
||||
let avatar = ImageCache.avatars.get(avatarURL) {
|
||||
avatarImage = Self.renderAvatar(avatar.image)
|
||||
self.avatarStyle = Preferences.shared.avatarStyle
|
||||
}
|
||||
|
||||
let image = avatarImage ?? UIImage(systemName: "person")!
|
||||
super.init(title: "My Profile", image: image, identifier: NewMainTabBarViewController.Tab.myProfile.rawValue, viewControllerProvider: viewControllerProvider)
|
||||
|
||||
if avatarImage == nil {
|
||||
Task {
|
||||
await updateAvatar()
|
||||
}
|
||||
}
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(preferencesChanged), name: .preferencesChanged, object: nil)
|
||||
}
|
||||
|
||||
private func updateAvatar() async {
|
||||
guard let account = try? await mastodonController.getOwnAccount(),
|
||||
let avatarURL = account.avatar,
|
||||
let image = await ImageCache.avatars.get(avatarURL).1 else {
|
||||
return
|
||||
}
|
||||
|
||||
let maybeGrayscale = await ImageGrayscalifier.convertIfNecessary(url: avatarURL, image: image) ?? image
|
||||
let rendered = Self.renderAvatar(maybeGrayscale)
|
||||
|
||||
self.avatarStyle = Preferences.shared.avatarStyle
|
||||
self.image = rendered
|
||||
}
|
||||
|
||||
private static func renderAvatar(_ image: UIImage) -> UIImage {
|
||||
let size = MainSidebarMyProfileCollectionViewCell.avatarImageSize
|
||||
let radius = Preferences.shared.avatarStyle.cornerRadiusFraction * size
|
||||
let rect = CGRect(x: 0, y: 0, width: size, height: size)
|
||||
let renderer = UIGraphicsImageRenderer(bounds: rect)
|
||||
let rendered = renderer.image { ctx in
|
||||
UIBezierPath(roundedRect: rect, cornerRadius: radius).addClip()
|
||||
image.draw(in: rect)
|
||||
}
|
||||
return rendered.withRenderingMode(.alwaysOriginal)
|
||||
}
|
||||
|
||||
@objc private func preferencesChanged() {
|
||||
if avatarStyle != nil,
|
||||
avatarStyle != Preferences.shared.avatarStyle {
|
||||
Task {
|
||||
await updateAvatar()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue