quote replies in progress

This commit is contained in:
Lumaa 2024-01-03 09:55:18 +01:00
parent bafdbe6c8f
commit 3b7937c085
3 changed files with 219 additions and 10 deletions

View File

@ -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 {

View File

@ -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/"
}

View File

@ -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
}
}
}