mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2025-01-22 13:58:08 +00:00
Display pinned statuses on profile
This commit is contained in:
parent
e9991020ec
commit
a1681c3f1b
8 changed files with 95 additions and 8 deletions
|
@ -57,6 +57,9 @@ public struct AccountDetailView: View {
|
|||
|
||||
switch viewModel.tabState {
|
||||
case .statuses:
|
||||
if viewModel.selectedTab == .statuses {
|
||||
pinnedPostsView
|
||||
}
|
||||
StatusesListView(fetcher: viewModel)
|
||||
case let .followedTags(tags):
|
||||
makeTagsListView(tags: tags)
|
||||
|
@ -295,6 +298,24 @@ public struct AccountDetailView: View {
|
|||
Text("Enter the name for your list")
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var pinnedPostsView: some View {
|
||||
if !viewModel.pinned.isEmpty {
|
||||
ForEach(viewModel.pinned) { status in
|
||||
VStack(alignment: .leading) {
|
||||
Label("Pinned post", systemImage: "pin.fill")
|
||||
.font(.footnote)
|
||||
.foregroundColor(.gray)
|
||||
.fontWeight(.semibold)
|
||||
StatusRowView(viewModel: .init(status: status))
|
||||
}
|
||||
.padding(.horizontal, .layoutPadding)
|
||||
Divider()
|
||||
.padding(.vertical, .dividerPadding)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AccountDetailView_Previews: PreviewProvider {
|
||||
|
|
|
@ -59,6 +59,7 @@ class AccountDetailViewModel: ObservableObject, StatusesFetcher {
|
|||
@Published var statusesState: StatusesState = .loading
|
||||
|
||||
@Published var relationship: Relationshionship?
|
||||
@Published var pinned: [Status] = []
|
||||
@Published var favourites: [Status] = []
|
||||
private var favouritesNextPage: LinkHandler?
|
||||
@Published var followedTags: [Tag] = []
|
||||
|
@ -137,7 +138,17 @@ class AccountDetailViewModel: ObservableObject, StatusesFetcher {
|
|||
sinceId: nil,
|
||||
tag: nil,
|
||||
onlyMedia: selectedTab == .media ? true : nil,
|
||||
excludeReplies: selectedTab == .statuses && !isCurrentUser ? true : nil))
|
||||
excludeReplies: selectedTab == .statuses && !isCurrentUser ? true : nil,
|
||||
pinned: nil))
|
||||
if selectedTab == .statuses {
|
||||
pinned =
|
||||
try await client.get(endpoint: Accounts.statuses(id: accountId,
|
||||
sinceId: nil,
|
||||
tag: nil,
|
||||
onlyMedia: nil,
|
||||
excludeReplies: nil,
|
||||
pinned: true))
|
||||
}
|
||||
if isCurrentUser {
|
||||
(favourites, favouritesNextPage) = try await client.getWithLink(endpoint: Accounts.favourites(sinceId: nil))
|
||||
}
|
||||
|
@ -159,7 +170,8 @@ class AccountDetailViewModel: ObservableObject, StatusesFetcher {
|
|||
sinceId: lastId,
|
||||
tag: nil,
|
||||
onlyMedia: selectedTab == .media ? true : nil,
|
||||
excludeReplies: selectedTab == .statuses && !isCurrentUser ? true : nil))
|
||||
excludeReplies: selectedTab == .statuses && !isCurrentUser ? true : nil,
|
||||
pinned: nil))
|
||||
statuses.append(contentsOf: newStatuses)
|
||||
tabState = .statuses(statusesState: .display(statuses: statuses,
|
||||
nextPageState: newStatuses.count < 20 ? .none : .hasNextPage))
|
||||
|
|
|
@ -6,7 +6,12 @@ public enum Accounts: Endpoint {
|
|||
case followedTags
|
||||
case featuredTags(id: String)
|
||||
case verifyCredentials
|
||||
case statuses(id: String, sinceId: String?, tag: String?, onlyMedia: Bool?, excludeReplies: Bool?)
|
||||
case statuses(id: String,
|
||||
sinceId: String?,
|
||||
tag: String?,
|
||||
onlyMedia: Bool?,
|
||||
excludeReplies: Bool?,
|
||||
pinned: Bool?)
|
||||
case relationships(ids: [String])
|
||||
case follow(id: String)
|
||||
case unfollow(id: String)
|
||||
|
@ -28,7 +33,7 @@ public enum Accounts: Endpoint {
|
|||
return "accounts/\(id)/featured_tags"
|
||||
case .verifyCredentials:
|
||||
return "accounts/verify_credentials"
|
||||
case .statuses(let id, _, _, _, _):
|
||||
case .statuses(let id, _, _, _, _, _):
|
||||
return "accounts/\(id)/statuses"
|
||||
case .relationships:
|
||||
return "accounts/relationships"
|
||||
|
@ -51,7 +56,7 @@ public enum Accounts: Endpoint {
|
|||
|
||||
public func queryItems() -> [URLQueryItem]? {
|
||||
switch self {
|
||||
case .statuses(_, let sinceId, let tag, let onlyMedia, let excludeReplies):
|
||||
case .statuses(_, let sinceId, let tag, let onlyMedia, let excludeReplies, let pinned):
|
||||
var params: [URLQueryItem] = []
|
||||
if let tag {
|
||||
params.append(.init(name: "tagged", value: tag))
|
||||
|
@ -65,6 +70,9 @@ public enum Accounts: Endpoint {
|
|||
if let excludeReplies {
|
||||
params.append(.init(name: "exclude_replies", value: excludeReplies ? "true" : "fals"))
|
||||
}
|
||||
if let pinned {
|
||||
params.append(.init(name: "pinned", value: pinned ? "true" : "false"))
|
||||
}
|
||||
return params
|
||||
case let .relationships(ids):
|
||||
return ids.map {
|
||||
|
|
|
@ -20,6 +20,8 @@ public enum Statuses: Endpoint {
|
|||
case unreblog(id: String)
|
||||
case rebloggedBy(id: String, maxId: String?)
|
||||
case favouritedBy(id: String, maxId: String?)
|
||||
case pin(id: String)
|
||||
case unpin(id: String)
|
||||
|
||||
public func path() -> String {
|
||||
switch self {
|
||||
|
@ -43,6 +45,10 @@ public enum Statuses: Endpoint {
|
|||
return "statuses/\(id)/reblogged_by"
|
||||
case .favouritedBy(let id, _):
|
||||
return "statuses/\(id)/favourited_by"
|
||||
case let .pin(id):
|
||||
return "statuses/\(id)/pin"
|
||||
case let .unpin(id):
|
||||
return "statuses/\(id)/unpin"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ public struct StatusesListView<Fetcher>: View where Fetcher: StatusesFetcher {
|
|||
StatusRowView(viewModel: .init(status: status, isCompact: false))
|
||||
.redacted(reason: .placeholder)
|
||||
.shimmering()
|
||||
.padding(.horizontal, .layoutPadding)
|
||||
Divider()
|
||||
.padding(.vertical, .dividerPadding)
|
||||
}
|
||||
|
@ -26,6 +27,7 @@ public struct StatusesListView<Fetcher>: View where Fetcher: StatusesFetcher {
|
|||
case let .display(statuses, nextPageState):
|
||||
ForEach(statuses, id: \.viewId) { status in
|
||||
StatusRowView(viewModel: .init(status: status, isCompact: false))
|
||||
.padding(.horizontal, .layoutPadding)
|
||||
Divider()
|
||||
.padding(.vertical, .dividerPadding)
|
||||
}
|
||||
|
@ -45,7 +47,6 @@ public struct StatusesListView<Fetcher>: View where Fetcher: StatusesFetcher {
|
|||
}
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, .layoutPadding)
|
||||
}
|
||||
|
||||
private var loadingRow: some View {
|
||||
|
@ -54,5 +55,6 @@ public struct StatusesListView<Fetcher>: View where Fetcher: StatusesFetcher {
|
|||
ProgressView()
|
||||
Spacer()
|
||||
}
|
||||
.padding(.horizontal, .layoutPadding)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -249,8 +249,19 @@ public struct StatusRowView: View {
|
|||
Label("View in Browser", systemImage: "safari")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if account.account?.id == viewModel.status.account.id {
|
||||
Button {
|
||||
Task {
|
||||
if viewModel.isPinned {
|
||||
await viewModel.unPin()
|
||||
} else {
|
||||
await viewModel.pin()
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
Label(viewModel.isPinned ? "Unpin": "Pin", systemImage: viewModel.isPinned ? "pin.fill" : "pin")
|
||||
}
|
||||
Button {
|
||||
routeurPath.presentedSheet = .editStatusEditor(status: viewModel.status)
|
||||
} label: {
|
||||
|
|
|
@ -11,6 +11,7 @@ public class StatusRowViewModel: ObservableObject {
|
|||
@Published var favouritesCount: Int
|
||||
@Published var isFavourited: Bool
|
||||
@Published var isReblogged: Bool
|
||||
@Published var isPinned: Bool
|
||||
@Published var reblogsCount: Int
|
||||
@Published var repliesCount: Int
|
||||
@Published var embededStatus: Status?
|
||||
|
@ -33,9 +34,11 @@ public class StatusRowViewModel: ObservableObject {
|
|||
if let reblog = status.reblog {
|
||||
self.isFavourited = reblog.favourited == true
|
||||
self.isReblogged = reblog.reblogged == true
|
||||
self.isPinned = reblog.pinned == true
|
||||
} else {
|
||||
self.isFavourited = status.favourited == true
|
||||
self.isReblogged = status.reblogged == true
|
||||
self.isPinned = status.pinned == true
|
||||
}
|
||||
self.favouritesCount = status.reblog?.favouritesCount ?? status.favouritesCount
|
||||
self.reblogsCount = status.reblog?.reblogsCount ?? status.reblogsCount
|
||||
|
@ -129,6 +132,28 @@ public class StatusRowViewModel: ObservableObject {
|
|||
}
|
||||
}
|
||||
|
||||
func pin() async {
|
||||
guard let client, client.isAuth else { return }
|
||||
isPinned = true
|
||||
do {
|
||||
let status: Status = try await client.post(endpoint: Statuses.pin(id: status.reblog?.id ?? status.id))
|
||||
updateFromStatus(status: status)
|
||||
} catch {
|
||||
isPinned = false
|
||||
}
|
||||
}
|
||||
|
||||
func unPin() async {
|
||||
guard let client, client.isAuth else { return }
|
||||
isPinned = false
|
||||
do {
|
||||
let status: Status = try await client.post(endpoint: Statuses.unpin(id: status.reblog?.id ?? status.id))
|
||||
updateFromStatus(status: status)
|
||||
} catch {
|
||||
isPinned = true
|
||||
}
|
||||
}
|
||||
|
||||
func delete() async {
|
||||
guard let client else { return }
|
||||
do {
|
||||
|
@ -140,9 +165,11 @@ public class StatusRowViewModel: ObservableObject {
|
|||
if let reblog = status.reblog {
|
||||
isFavourited = reblog.favourited == true
|
||||
isReblogged = reblog.reblogged == true
|
||||
isPinned = reblog.pinned == true
|
||||
} else {
|
||||
isFavourited = status.favourited == true
|
||||
isReblogged = status.reblogged == true
|
||||
isPinned = status.pinned == true
|
||||
}
|
||||
favouritesCount = status.reblog?.favouritesCount ?? status.favouritesCount
|
||||
reblogsCount = status.reblog?.reblogsCount ?? status.reblogsCount
|
||||
|
|
|
@ -61,7 +61,7 @@ public enum TimelineFilter: Hashable, Equatable {
|
|||
case let .list(list): return Timelines.list(listId: list.id, sinceId: sinceId, maxId: maxId, minId: minId)
|
||||
case let .hashtag(tag, accountId):
|
||||
if let accountId {
|
||||
return Accounts.statuses(id: accountId, sinceId: nil, tag: tag, onlyMedia: nil, excludeReplies: nil)
|
||||
return Accounts.statuses(id: accountId, sinceId: nil, tag: tag, onlyMedia: nil, excludeReplies: nil, pinned: nil)
|
||||
} else {
|
||||
return Timelines.hashtag(tag: tag, maxId: maxId)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue