visionOS: Improve suggested profile card appearance

This commit is contained in:
Shadowfacts 2023-11-08 21:49:21 -05:00
parent a846954dcd
commit 01bbfc31f2
3 changed files with 94 additions and 0 deletions

View File

@ -255,6 +255,7 @@
D6B9366F2828452F00237D0E /* SavedHashtag.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B9366E2828452F00237D0E /* SavedHashtag.swift */; };
D6B936712829F72900237D0E /* NSManagedObjectContext+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B936702829F72900237D0E /* NSManagedObjectContext+Helpers.swift */; };
D6BC74842AFC3DF9000DD603 /* TrendingLinkCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BC74832AFC3DF9000DD603 /* TrendingLinkCardView.swift */; };
D6BC74862AFC4772000DD603 /* SuggestedProfileCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BC74852AFC4772000DD603 /* SuggestedProfileCardView.swift */; };
D6BC9DB1232C61BC002CA326 /* NotificationsPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BC9DB0232C61BC002CA326 /* NotificationsPageViewController.swift */; };
D6BC9DB3232D4C07002CA326 /* WellnessPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BC9DB2232D4C07002CA326 /* WellnessPrefsView.swift */; };
D6BC9DD7232D7811002CA326 /* TimelinesPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BC9DD6232D7811002CA326 /* TimelinesPageViewController.swift */; };
@ -655,6 +656,7 @@
D6B9366E2828452F00237D0E /* SavedHashtag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavedHashtag.swift; sourceTree = "<group>"; };
D6B936702829F72900237D0E /* NSManagedObjectContext+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+Helpers.swift"; sourceTree = "<group>"; };
D6BC74832AFC3DF9000DD603 /* TrendingLinkCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingLinkCardView.swift; sourceTree = "<group>"; };
D6BC74852AFC4772000DD603 /* SuggestedProfileCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestedProfileCardView.swift; sourceTree = "<group>"; };
D6BC9DB0232C61BC002CA326 /* NotificationsPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsPageViewController.swift; sourceTree = "<group>"; };
D6BC9DB2232D4C07002CA326 /* WellnessPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WellnessPrefsView.swift; sourceTree = "<group>"; };
D6BC9DD6232D7811002CA326 /* TimelinesPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinesPageViewController.swift; sourceTree = "<group>"; };
@ -907,6 +909,7 @@
D6BC74832AFC3DF9000DD603 /* TrendingLinkCardView.swift */,
D601FA81297EEC3F00A8E8B5 /* SuggestedProfileCardCollectionViewCell.swift */,
D601FA82297EEC3F00A8E8B5 /* SuggestedProfileCardCollectionViewCell.xib */,
D6BC74852AFC4772000DD603 /* SuggestedProfileCardView.swift */,
D693A72925CF8C1E003A14E2 /* ProfileDirectoryViewController.swift */,
D693A72D25CF91C6003A14E2 /* FeaturedProfileCollectionViewCell.swift */,
D693A72E25CF91C6003A14E2 /* FeaturedProfileCollectionViewCell.xib */,
@ -1981,6 +1984,7 @@
D61F759B29384F9C00C0B37F /* FilterMO.swift in Sources */,
D68FEC4F232C5BC300C84F23 /* SegmentedPageViewController.swift in Sources */,
D64AAE9126C80DC600FC57FB /* ToastView.swift in Sources */,
D6BC74862AFC4772000DD603 /* SuggestedProfileCardView.swift in Sources */,
0450531F22B0097E00100BA2 /* Timline+UI.swift in Sources */,
D6C7D27D22B6EBF800071952 /* AttachmentsContainerView.swift in Sources */,
D61F75942936F0DA00C0B37F /* FollowedHashtag.swift in Sources */,

View File

@ -0,0 +1,78 @@
//
// SuggestedProfileCardView.swift
// Tusker
//
// Created by Shadowfacts on 11/8/23.
// Copyright © 2023 Shadowfacts. All rights reserved.
//
#if os(visionOS)
import SwiftUI
struct SuggestedProfileCardView: View {
let account: AccountMO
var body: some View {
VStack {
HeaderLayout {
AsyncImage(url: account.header) { image in
image
.resizable()
} placeholder: {
Rectangle().fill(.tertiary)
}
AsyncImage(url: account.avatar) { image in
image
.resizable()
.clipShape(RoundedRectangle(cornerRadius: 5))
} placeholder: {
Rectangle().fill(.tertiary)
}
VStack(alignment: .leading) {
AccountDisplayNameView(account: account, textStyle: .title, emojiSize: 24)
Text(verbatim: "@\(account.acct)")
}
}
NoteTextView(note: account.note)
}
.glassBackgroundEffect(in: RoundedRectangle(cornerRadius: 12.5))
}
}
private struct HeaderLayout: Layout {
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
let acceptedWidth = proposal.width ?? 200
let avatarSize = subviews[1].sizeThatFits(ProposedViewSize(width: 86, height: 86))
let accountInfoSize = subviews[2].sizeThatFits(ProposedViewSize(width: acceptedWidth - 8 - avatarSize.width, height: 43))
return CGSize(width: proposal.width ?? 200, height: 100 + 4 + accountInfoSize.height)
}
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
let headerSize = subviews[0].sizeThatFits(ProposedViewSize(width: bounds.width, height: 100))
subviews[0].place(at: .zero, proposal: ProposedViewSize(headerSize))
let avatarSize = subviews[1].sizeThatFits(ProposedViewSize(width: 86, height: 86))
subviews[1].place(at: CGPoint(x: 8, y: headerSize.height), anchor: .leading, proposal: ProposedViewSize(avatarSize))
subviews[2].place(at: CGPoint(x: 8 + avatarSize.width + 8, y: headerSize.height + 4), proposal: ProposedViewSize(width: bounds.width - 8 - avatarSize.width - 8, height: 43))
}
}
private struct NoteTextView: UIViewRepresentable {
typealias UIViewType = StatusContentTextView
let note: String
func makeUIView(context: Context) -> StatusContentTextView {
let view = StatusContentTextView()
view.isUserInteractionEnabled = false
view.isScrollEnabled = true
view.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
return view
}
func updateUIView(_ uiView: StatusContentTextView, context: Context) {
uiView.setTextFromHtml(note)
}
}
//#Preview {
// SuggestedProfileCardView()
//}
#endif

View File

@ -163,10 +163,22 @@ class TrendsViewController: UIViewController, CollectionViewController {
// TODO: filter trends
cell.updateUI(statusID: item.0, state: item.1, filterResult: .allow, precomputedContent: nil)
}
#if os(visionOS)
let accountCell = UICollectionView.CellRegistration<UICollectionViewCell, (String, Suggestion.Source)> { [unowned self] cell, indexPath, item in
if let account = self.mastodonController.persistentContainer.account(for: item.0) {
cell.contentConfiguration = UIHostingConfiguration(content: {
SuggestedProfileCardView(account: account)
})
} else {
cell.contentConfiguration = nil
}
}
#else
let accountCell = UICollectionView.CellRegistration<SuggestedProfileCardCollectionViewCell, (String, Suggestion.Source)>(cellNib: UINib(nibName: "SuggestedProfileCardCollectionViewCell", bundle: .main)) { [unowned self] cell, indexPath, item in
cell.delegate = self
cell.updateUI(accountID: item.0, source: item.1)
}
#endif
let confirmLoadMoreCell = UICollectionView.CellRegistration<ConfirmLoadMoreCollectionViewCell, Bool> { [unowned self] cell, indexPath, isLoading in
cell.confirmLoadMore = self.confirmLoadMoreStatuses
cell.isLoading = isLoading