Very basic status post

This commit is contained in:
Thomas Ricouard 2022-12-25 08:17:16 +01:00
parent e569bb1d74
commit 8df70043cb
8 changed files with 95 additions and 25 deletions

View file

@ -42,7 +42,7 @@
"location" : "https://github.com/Dimillian/TextView", "location" : "https://github.com/Dimillian/TextView",
"state" : { "state" : {
"branch" : "main", "branch" : "main",
"revision" : "0316b7df487f5e6f1b199d326e903310b9044c0d" "revision" : "002a062d6275a2b5352f0ea6ff6c22aaadd19b55"
} }
} }
], ],

View file

@ -32,8 +32,8 @@ extension View {
func withSheetDestinations(sheetDestinations: Binding<SheetDestinations?>) -> some View { func withSheetDestinations(sheetDestinations: Binding<SheetDestinations?>) -> some View {
self.sheet(item: sheetDestinations) { destination in self.sheet(item: sheetDestinations) { destination in
switch destination { switch destination {
case .statusEditor: case let .statusEditor(replyToStatus):
StatusEditorView() StatusEditorView(inReplyTo: replyToStatus)
} }
} }
} }

View file

@ -14,7 +14,7 @@ public enum RouteurDestinations: Hashable {
} }
public enum SheetDestinations: Identifiable { public enum SheetDestinations: Identifiable {
case statusEditor(replyToStatus: String?) case statusEditor(replyToStatus: Status?)
public var id: String { public var id: String {
switch self { switch self {

View file

@ -1,6 +1,10 @@
import Foundation import Foundation
public enum Statuses: Endpoint { public enum Statuses: Endpoint {
case postStatus(status: String,
inReplyTo: String?,
mediaIds: [String]?,
spoilerText: String?)
case status(id: String) case status(id: String)
case context(id: String) case context(id: String)
case favourite(id: String) case favourite(id: String)
@ -12,6 +16,8 @@ public enum Statuses: Endpoint {
public func path() -> String { public func path() -> String {
switch self { switch self {
case .postStatus:
return "statuses"
case .status(let id): case .status(let id):
return "statuses/\(id)" return "statuses/\(id)"
case .context(let id): case .context(let id):
@ -33,6 +39,20 @@ public enum Statuses: Endpoint {
public func queryItems() -> [URLQueryItem]? { public func queryItems() -> [URLQueryItem]? {
switch self { switch self {
case let .postStatus(status, inReplyTo, mediaIds, spoilerText):
var params: [URLQueryItem] = [.init(name: "status", value: status)]
if let inReplyTo {
params.append(.init(name: "in_reply_to_id", value: inReplyTo))
}
if let mediaIds {
for mediaId in mediaIds {
params.append(.init(name: "media_ids[]", value: mediaId))
}
}
if let spoilerText {
params.append(.init(name: "spoiler_text", value: spoilerText))
}
return params
case let .rebloggedBy(_, maxId): case let .rebloggedBy(_, maxId):
return makePaginationParam(sinceId: nil, maxId: maxId) return makePaginationParam(sinceId: nil, maxId: maxId)
case let .favouritedBy(_, maxId): case let .favouritedBy(_, maxId):

View file

@ -3,25 +3,36 @@ import Accounts
import Env import Env
import DesignSystem import DesignSystem
import TextView import TextView
import Models
import Network
public struct StatusEditorView: View { public struct StatusEditorView: View {
@EnvironmentObject private var client: Client
@EnvironmentObject private var currentAccount: CurrentAccount @EnvironmentObject private var currentAccount: CurrentAccount
@Environment(\.dismiss) private var dismiss @Environment(\.dismiss) private var dismiss
@StateObject private var viewModel = StatusEditorViewModel() @StateObject private var viewModel: StatusEditorViewModel
public init() { public init(inReplyTo: Status?) {
_viewModel = StateObject(wrappedValue: .init(inReplyTo: inReplyTo))
} }
public var body: some View { public var body: some View {
NavigationStack { NavigationStack {
VStack { ZStack(alignment: .bottom) {
accountHeaderView VStack {
TextView($viewModel.statusText) accountHeaderView
.placeholder("What's on your mind") TextView($viewModel.statusText)
.foregroundColor(.clear) .placeholder("What's on your mind")
Spacer() .foregroundColor(.clear)
Spacer()
}
accessoryView
.padding(.bottom, 12)
}
.onAppear {
viewModel.client = client
viewModel.insertReplyTo()
} }
.padding(.horizontal, DS.Constants.layoutPadding) .padding(.horizontal, DS.Constants.layoutPadding)
.navigationTitle("New post") .navigationTitle("New post")
@ -29,7 +40,10 @@ public struct StatusEditorView: View {
.toolbar { .toolbar {
ToolbarItem(placement: .navigationBarTrailing) { ToolbarItem(placement: .navigationBarTrailing) {
Button { Button {
dismiss() Task {
_ = await viewModel.postStatus()
dismiss()
}
} label: { } label: {
Text("Post") Text("Post")
} }
@ -61,5 +75,16 @@ public struct StatusEditorView: View {
} }
} }
} }
private var accessoryView: some View {
HStack {
Button {
} label: {
Image(systemName: "photo.fill.on.rectangle.fill")
}
Spacer()
}
}
} }

View file

@ -1,5 +1,7 @@
import SwiftUI import SwiftUI
import DesignSystem import DesignSystem
import Models
import Network
@MainActor @MainActor
class StatusEditorViewModel: ObservableObject { class StatusEditorViewModel: ObservableObject {
@ -10,12 +12,37 @@ class StatusEditorViewModel: ObservableObject {
} }
} }
var client: Client?
private var internalUpdate: Bool = false private var internalUpdate: Bool = false
private var inReplyTo: Status?
init(inReplyTo: Status?) {
self.inReplyTo = inReplyTo
}
func postStatus() async -> Status? {
guard let client else { return nil }
do {
let status: Status = try await client.post(endpoint: Statuses.postStatus(status: statusText.string,
inReplyTo: inReplyTo?.id,
mediaIds: nil,
spoilerText: nil))
return status
} catch {
return nil
}
}
func insertReplyTo() {
if let inReplyTo {
statusText = .init(string: "@\(inReplyTo.account.acct) ")
}
}
func highlightMeta() { func highlightMeta() {
let mutableString = NSMutableAttributedString(attributedString: statusText) let mutableString = NSMutableAttributedString(attributedString: statusText)
let hashtagPattern = "(#+[a-zA-Z0-9(_)]{1,})" let hashtagPattern = "(#+[a-zA-Z0-9(_)]{1,})"
let mentionPattern = "(@+[a-zA-Z0-9(_)]{1,})" let mentionPattern = "(@+[a-zA-Z0-9(_).]{1,})"
var ranges: [NSRange] = [NSRange]() var ranges: [NSRange] = [NSRange]()
let hashtagRegex = try! NSRegularExpression(pattern: hashtagPattern, options: []) let hashtagRegex = try! NSRegularExpression(pattern: hashtagPattern, options: [])

View file

@ -128,7 +128,7 @@ struct StatusActionsView: View {
generator.notificationOccurred(.success) generator.notificationOccurred(.success)
switch action { switch action {
case .respond: case .respond:
routeurPath.navigate(to: .statusDetail(id: viewModel.status.reblog?.id ?? viewModel.status.id)) routeurPath.presentedSheet = .statusEditor(replyToStatus: viewModel.status)
case .favourite: case .favourite:
if viewModel.isFavourited { if viewModel.isFavourited {
await viewModel.unFavourite() await viewModel.unFavourite()

View file

@ -12,15 +12,13 @@ class TimelineViewModel: ObservableObject, StatusesFetcher {
@Published var statusesState: StatusesState = .loading @Published var statusesState: StatusesState = .loading
@Published var timeline: TimelineFilter = .pub { @Published var timeline: TimelineFilter = .pub {
didSet { didSet {
if oldValue != timeline || statuses.isEmpty { Task {
Task { await fetchStatuses()
await fetchStatuses() switch timeline {
switch timeline { case let .hashtag(tag, _):
case let .hashtag(tag, _): await fetchTag(id: tag)
await fetchTag(id: tag) default:
default: break
break
}
} }
} }
} }