mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2025-02-16 17:55:13 +00:00
Account detail: Add also followed by section
This commit is contained in:
parent
084dd18362
commit
fc77dd14fe
5 changed files with 94 additions and 25 deletions
|
@ -34,8 +34,10 @@ public struct AccountDetailView: View {
|
||||||
ScrollViewOffsetReader { offset in
|
ScrollViewOffsetReader { offset in
|
||||||
self.scrollOffset = offset
|
self.scrollOffset = offset
|
||||||
} content: {
|
} content: {
|
||||||
LazyVStack {
|
LazyVStack(alignment: .leading) {
|
||||||
headerView
|
headerView
|
||||||
|
familliarFollowers
|
||||||
|
.offset(y: -36)
|
||||||
featuredTagsView
|
featuredTagsView
|
||||||
.offset(y: -36)
|
.offset(y: -36)
|
||||||
if isCurrentUser {
|
if isCurrentUser {
|
||||||
|
@ -151,6 +153,31 @@ public struct AccountDetailView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var familliarFollowers: some View {
|
||||||
|
if !viewModel.familliarFollowers.isEmpty {
|
||||||
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
|
Text("Also followed by")
|
||||||
|
.font(.headline)
|
||||||
|
.padding(.leading, DS.Constants.layoutPadding)
|
||||||
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
|
LazyHStack(spacing: 0) {
|
||||||
|
ForEach(viewModel.familliarFollowers) { account in
|
||||||
|
AvatarView(url: account.avatar, size: .badge)
|
||||||
|
.onTapGesture {
|
||||||
|
routeurPath.navigate(to: .accountDetailWithAccount(account: account))
|
||||||
|
}
|
||||||
|
.padding(.leading, -4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.leading, DS.Constants.layoutPadding + 4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.top, 2)
|
||||||
|
.padding(.bottom, 12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var fieldSheetView: some View {
|
private var fieldSheetView: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
List {
|
List {
|
||||||
|
|
|
@ -50,6 +50,7 @@ class AccountDetailViewModel: ObservableObject, StatusesFetcher {
|
||||||
@Published var followedTags: [Tag] = []
|
@Published var followedTags: [Tag] = []
|
||||||
@Published var featuredTags: [FeaturedTag] = []
|
@Published var featuredTags: [FeaturedTag] = []
|
||||||
@Published var fields: [Account.Field] = []
|
@Published var fields: [Account.Field] = []
|
||||||
|
@Published var familliarFollowers: [Account] = []
|
||||||
@Published var selectedTab = Tab.statuses {
|
@Published var selectedTab = Tab.statuses {
|
||||||
didSet {
|
didSet {
|
||||||
reloadTabState()
|
reloadTabState()
|
||||||
|
@ -77,18 +78,25 @@ class AccountDetailViewModel: ObservableObject, StatusesFetcher {
|
||||||
func fetchAccount() async {
|
func fetchAccount() async {
|
||||||
guard let client else { return }
|
guard let client else { return }
|
||||||
do {
|
do {
|
||||||
let account: Account = try await client.get(endpoint: Accounts.accounts(id: accountId))
|
async let account: Account = client.get(endpoint: Accounts.accounts(id: accountId))
|
||||||
self.fields = account.fields
|
async let followedTags: [Tag] = client.get(endpoint: Accounts.followedTags)
|
||||||
if isCurrentUser {
|
async let relationships: [Relationshionship] = client.get(endpoint: Accounts.relationships(id: accountId))
|
||||||
self.followedTags = try await client.get(endpoint: Accounts.followedTags)
|
async let featuredTags: [FeaturedTag] = client.get(endpoint: Accounts.featuredTags(id: accountId))
|
||||||
} else {
|
async let familliarFollowers: [FamilliarAccounts] = client.get(endpoint: Accounts.familiarFollowers(withAccount: accountId))
|
||||||
let relationships: [Relationshionship] = try await client.get(endpoint: Accounts.relationships(id: accountId))
|
let loadedAccount = try await account
|
||||||
self.relationship = relationships.first
|
self.featuredTags = try await featuredTags
|
||||||
}
|
|
||||||
self.featuredTags = try await client.get(endpoint: Accounts.featuredTags(id: accountId))
|
|
||||||
self.featuredTags.sort { $0.statusesCountInt > $1.statusesCountInt }
|
self.featuredTags.sort { $0.statusesCountInt > $1.statusesCountInt }
|
||||||
self.title = account.displayName
|
self.fields = loadedAccount.fields
|
||||||
accountState = .data(account: account)
|
self.title = loadedAccount.displayName
|
||||||
|
if isCurrentUser {
|
||||||
|
self.followedTags = try await followedTags
|
||||||
|
} else {
|
||||||
|
let relationships = try await relationships
|
||||||
|
self.relationship = relationships.first
|
||||||
|
self.familliarFollowers = try await familliarFollowers.first?.accounts ?? []
|
||||||
|
}
|
||||||
|
self.account = loadedAccount
|
||||||
|
accountState = .data(account: loadedAccount)
|
||||||
} catch {
|
} catch {
|
||||||
accountState = .error(error: error)
|
accountState = .error(error: error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +1,56 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
public struct AvatarView: View {
|
public struct AvatarView: View {
|
||||||
|
public enum Size {
|
||||||
|
case profile, badge
|
||||||
|
|
||||||
|
var size: CGSize {
|
||||||
|
switch self {
|
||||||
|
case .profile:
|
||||||
|
return .init(width: 40, height: 40)
|
||||||
|
case .badge:
|
||||||
|
return .init(width: 28, height: 28)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Environment(\.redactionReasons) private var reasons
|
@Environment(\.redactionReasons) private var reasons
|
||||||
public let url: URL
|
public let url: URL
|
||||||
|
public let size: Size
|
||||||
|
|
||||||
public init(url: URL) {
|
public init(url: URL, size: Size = .profile) {
|
||||||
self.url = url
|
self.url = url
|
||||||
|
self.size = size
|
||||||
}
|
}
|
||||||
|
|
||||||
public var body: some View {
|
public var body: some View {
|
||||||
if reasons == .placeholder {
|
if reasons == .placeholder {
|
||||||
RoundedRectangle(cornerRadius: 4)
|
RoundedRectangle(cornerRadius: size == .profile ? 4 : size.size.width / 2)
|
||||||
.fill(.gray)
|
.fill(.gray)
|
||||||
.frame(maxWidth: 40, maxHeight: 40)
|
.frame(maxWidth: size.size.width, maxHeight: size.size.height)
|
||||||
} else {
|
} else {
|
||||||
AsyncImage(
|
AsyncImage(url: url) { phase in
|
||||||
url: url,
|
switch phase {
|
||||||
content: { image in
|
case .empty:
|
||||||
|
if size == .badge {
|
||||||
|
Circle()
|
||||||
|
.fill(.gray)
|
||||||
|
.frame(maxWidth: size.size.width, maxHeight: size.size.height)
|
||||||
|
} else {
|
||||||
|
ProgressView()
|
||||||
|
.frame(maxWidth: size.size.width, maxHeight: size.size.height)
|
||||||
|
}
|
||||||
|
case let .success(image):
|
||||||
image.resizable()
|
image.resizable()
|
||||||
.aspectRatio(contentMode: .fit)
|
.aspectRatio(contentMode: .fit)
|
||||||
.cornerRadius(4)
|
.cornerRadius(size == .profile ? 4 : size.size.width / 2)
|
||||||
.frame(maxWidth: 40, maxHeight: 40)
|
.frame(maxWidth: size.size.width, maxHeight: size.size.height)
|
||||||
},
|
case .failure:
|
||||||
placeholder: {
|
EmptyView()
|
||||||
ProgressView()
|
@unknown default:
|
||||||
.frame(maxWidth: 40, maxHeight: 40)
|
EmptyView()
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,3 +49,8 @@ public struct Account: Codable, Identifiable, Equatable, Hashable {
|
||||||
emojis: [])
|
emojis: [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct FamilliarAccounts: Codable {
|
||||||
|
public let id: String
|
||||||
|
public let accounts: [Account]
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ public enum Accounts: Endpoint {
|
||||||
case relationships(id: String)
|
case relationships(id: String)
|
||||||
case follow(id: String)
|
case follow(id: String)
|
||||||
case unfollow(id: String)
|
case unfollow(id: String)
|
||||||
|
case familiarFollowers(withAccount: String)
|
||||||
|
|
||||||
public func path() -> String {
|
public func path() -> String {
|
||||||
switch self {
|
switch self {
|
||||||
|
@ -31,6 +32,8 @@ public enum Accounts: Endpoint {
|
||||||
return "accounts/\(id)/follow"
|
return "accounts/\(id)/follow"
|
||||||
case .unfollow(let id):
|
case .unfollow(let id):
|
||||||
return "accounts/\(id)/unfollow"
|
return "accounts/\(id)/unfollow"
|
||||||
|
case .familiarFollowers:
|
||||||
|
return "accounts/familiar_followers"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +50,8 @@ public enum Accounts: Endpoint {
|
||||||
return params
|
return params
|
||||||
case let .relationships(id):
|
case let .relationships(id):
|
||||||
return [.init(name: "id", value: id)]
|
return [.init(name: "id", value: id)]
|
||||||
|
case let .familiarFollowers(withAccount):
|
||||||
|
return [.init(name: "id[]", value: withAccount)]
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue