quote replies in progress
This commit is contained in:
parent
bafdbe6c8f
commit
3b7937c085
|
@ -11,6 +11,8 @@ struct CompactPostView: View {
|
|||
@State private var initialLike: Bool = false
|
||||
@State private var isLiked: Bool = false
|
||||
@State private var isReposted: Bool = false
|
||||
@State private var hasQuote: Bool = false
|
||||
@State private var quoteStatus: Status? = nil
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
|
@ -37,6 +39,13 @@ struct CompactPostView: View {
|
|||
isLiked = status.reblog != nil ? status.reblog!.favourited ?? false : status.favourited ?? false
|
||||
initialLike = isLiked
|
||||
isReposted = status.reblog != nil ? status.reblog!.reblogged ?? false : status.reblogged ?? false
|
||||
|
||||
let likeCount: Int = status.favouritesCount - (initialLike ? 1 : 0)
|
||||
let incrLike: Int = isLiked ? 1 : 0
|
||||
print("original: \(status.favouritesCount)\nmin1: \(likeCount)\nincr1: \(likeCount + incrLike)")
|
||||
}
|
||||
.task {
|
||||
await loadEmbeddedStatus()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,6 +133,16 @@ struct CompactPostView: View {
|
|||
if status.card != nil {
|
||||
PostCardView(card: status.card!)
|
||||
}
|
||||
|
||||
// if hasQuote {
|
||||
// if quoteStatus != nil {
|
||||
// //TODO: Fix profile picture and stats
|
||||
// QuotePostView(status: quoteStatus!)
|
||||
// } else {
|
||||
// ProgressView()
|
||||
// .progressViewStyle(.circular)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
//MARK: Action buttons
|
||||
|
@ -220,12 +239,12 @@ struct CompactPostView: View {
|
|||
}
|
||||
|
||||
if status.favouritesCount > 0 || isLiked {
|
||||
let i: Int = status.favouritesCount
|
||||
let favsCount: Int = i - (initialLike ? 1 : 0) + (isLiked ? 1 : 0)
|
||||
Text("status.favourites-\(favsCount)")
|
||||
let likeCount: Int = status.favouritesCount - (initialLike ? 1 : 0)
|
||||
let incrLike: Int = isLiked ? 1 : 0
|
||||
Text("status.favourites-\(likeCount + incrLike)")
|
||||
.monospacedDigit()
|
||||
.foregroundStyle(.gray)
|
||||
.contentTransition(.numericText(value: Double(favsCount)))
|
||||
.contentTransition(.numericText(value: Double(likeCount + incrLike)))
|
||||
.transaction { t in
|
||||
t.animation = .default
|
||||
}
|
||||
|
@ -245,11 +264,12 @@ struct CompactPostView: View {
|
|||
}
|
||||
|
||||
if status.reblog!.favouritesCount > 0 || isLiked {
|
||||
let favsCount: Int = (status.favouritesCount - (initialLike ? 1 : 0)) + (isLiked ? 1 : 0)
|
||||
Text("status.favourites-\(favsCount)")
|
||||
let likeCount: Int = status.reblog!.favouritesCount - (initialLike ? 1 : 0)
|
||||
let incrLike: Int = isLiked ? 1 : 0
|
||||
Text("status.favourites-\(likeCount + incrLike)")
|
||||
.monospacedDigit()
|
||||
.foregroundStyle(.gray)
|
||||
.contentTransition(.numericText(value: Double(favsCount)))
|
||||
.contentTransition(.numericText(value: Double(likeCount + incrLike)))
|
||||
.transaction { t in
|
||||
t.animation = .default
|
||||
}
|
||||
|
@ -258,6 +278,33 @@ struct CompactPostView: View {
|
|||
}
|
||||
}
|
||||
|
||||
private func embededStatusURL() -> URL? {
|
||||
let content = status.content
|
||||
if let client = accountManager.getClient() {
|
||||
if !content.statusesURLs.isEmpty, let url = content.statusesURLs.first, client.hasConnection(with: url) {
|
||||
return url
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadEmbeddedStatus() async {
|
||||
guard let url = embededStatusURL(), let client = accountManager.getClient() else { hasQuote = false; return }
|
||||
|
||||
do {
|
||||
hasQuote = true
|
||||
if url.absoluteString.contains(client.server), let id = Int(url.lastPathComponent) {
|
||||
quoteStatus = try await client.get(endpoint: Statuses.status(id: String(id)))
|
||||
} else {
|
||||
let results: SearchResults = try await client.get(endpoint: Search.search(query: url.absoluteString, type: "statuses", offset: 0, following: nil), forceVersion: .v2)
|
||||
quoteStatus = results.statuses.first
|
||||
}
|
||||
} catch {
|
||||
hasQuote = false
|
||||
quoteStatus = nil
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func actionButton(_ image: String, action: @escaping () -> Void) -> some View {
|
||||
Button {
|
||||
|
|
|
@ -3,11 +3,123 @@
|
|||
import SwiftUI
|
||||
|
||||
struct QuotePostView: View {
|
||||
@Environment(Navigator.self) private var navigator: Navigator
|
||||
var status: Status
|
||||
|
||||
var body: some View {
|
||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||
statusPost(status)
|
||||
.frame(width: 250)
|
||||
.padding(.horizontal, 10)
|
||||
.clipShape(.rect(cornerRadius: 15))
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 15)
|
||||
.stroke(.gray.opacity(0.3), lineWidth: 1)
|
||||
)
|
||||
.onTapGesture {
|
||||
if UIApplication.shared.canOpenURL(URL(string: status.url ?? .fallbackUrl)!) {
|
||||
UIApplication.shared.open(URL(string: status.url ?? .fallbackUrl)!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func statusPost(_ status: AnyStatus) -> some View {
|
||||
HStack(alignment: .top, spacing: 0) {
|
||||
// MARK: Profile picture
|
||||
if status.repliesCount > 0 {
|
||||
VStack {
|
||||
profilePicture
|
||||
.onTapGesture {
|
||||
navigator.navigate(to: .account(acc: status.account))
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Rectangle()
|
||||
.fill(Color.gray.opacity(0.3))
|
||||
.frame(width: 2.5)
|
||||
.clipShape(.capsule)
|
||||
.padding([.vertical], 5)
|
||||
|
||||
Spacer()
|
||||
|
||||
Image(systemName: "person.crop.circle")
|
||||
.resizable()
|
||||
.frame(width: 15, height: 15)
|
||||
.symbolRenderingMode(.monochrome)
|
||||
.foregroundStyle(Color.gray.opacity(0.3))
|
||||
.padding(.bottom, 2.5)
|
||||
}
|
||||
} else {
|
||||
profilePicture
|
||||
.onTapGesture {
|
||||
navigator.navigate(to: .account(acc: status.account))
|
||||
}
|
||||
}
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
// MARK: Status main content
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
Text(status.account.username)
|
||||
.multilineTextAlignment(.leading)
|
||||
.bold()
|
||||
.onTapGesture {
|
||||
navigator.navigate(to: .account(acc: status.account))
|
||||
}
|
||||
|
||||
if !status.content.asRawText.isEmpty {
|
||||
TextEmoji(status.content, emojis: status.emojis, language: status.language)
|
||||
.multilineTextAlignment(.leading)
|
||||
.frame(width: 250, alignment: .topLeading)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.font(.callout)
|
||||
}
|
||||
|
||||
if status.card != nil {
|
||||
PostCardView(card: status.card!, inQuote: true)
|
||||
}
|
||||
}
|
||||
.padding(.top)
|
||||
|
||||
// MARK: Status stats
|
||||
stats
|
||||
.padding(.top, 5)
|
||||
.padding(.bottom, status.repliesCount > 0 || status.favouritesCount > 0 ? 10 : 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var profilePicture: some View {
|
||||
OnlineImage(url: status.account.avatar, size: 40, useNuke: true)
|
||||
.frame(width: 25, height: 25)
|
||||
.padding(.horizontal)
|
||||
.clipShape(.circle)
|
||||
}
|
||||
|
||||
var stats: some View {
|
||||
//TODO: Put this in its own view (maybe?)
|
||||
HStack {
|
||||
if status.repliesCount > 0 {
|
||||
Text("status.replies-\(status.repliesCount)")
|
||||
.monospacedDigit()
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
|
||||
if status.repliesCount > 0 && status.favouritesCount > 0 {
|
||||
Text("•")
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
|
||||
if status.favouritesCount > 0 {
|
||||
Text("status.favourites-\(status.favouritesCount)")
|
||||
.monospacedDigit()
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
QuotePostView()
|
||||
private extension String {
|
||||
static let fallbackUrl = "https://joinmastodon.org/"
|
||||
}
|
||||
|
|
|
@ -1,3 +1,53 @@
|
|||
//Made by Lumaa
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct SearchResults: Decodable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case accounts, statuses, hashtags
|
||||
}
|
||||
|
||||
public let accounts: [Account]
|
||||
public var relationships: [Relationship] = []
|
||||
public let statuses: [Status]
|
||||
public let hashtags: [Tag]
|
||||
|
||||
public var isEmpty: Bool {
|
||||
accounts.isEmpty && statuses.isEmpty && hashtags.isEmpty
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchResults: Sendable {}
|
||||
|
||||
public enum Search: Endpoint {
|
||||
case search(query: String, type: String?, offset: Int?, following: Bool?)
|
||||
case accountsSearch(query: String, type: String?, offset: Int?, following: Bool?)
|
||||
|
||||
public func path() -> String {
|
||||
switch self {
|
||||
case .search:
|
||||
"search"
|
||||
case .accountsSearch:
|
||||
"accounts/search"
|
||||
}
|
||||
}
|
||||
|
||||
public func queryItems() -> [URLQueryItem]? {
|
||||
switch self {
|
||||
case let .search(query, type, offset, following),
|
||||
let .accountsSearch(query, type, offset, following):
|
||||
var params: [URLQueryItem] = [.init(name: "q", value: query)]
|
||||
if let type {
|
||||
params.append(.init(name: "type", value: type))
|
||||
}
|
||||
if let offset {
|
||||
params.append(.init(name: "offset", value: String(offset)))
|
||||
}
|
||||
if let following {
|
||||
params.append(.init(name: "following", value: following ? "true" : "false"))
|
||||
}
|
||||
params.append(.init(name: "resolve", value: "true"))
|
||||
return params
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue