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",
"state" : {
"branch" : "main",
"revision" : "0316b7df487f5e6f1b199d326e903310b9044c0d"
"revision" : "002a062d6275a2b5352f0ea6ff6c22aaadd19b55"
}
}
],

View File

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

View File

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

View File

@ -1,6 +1,10 @@
import Foundation
public enum Statuses: Endpoint {
case postStatus(status: String,
inReplyTo: String?,
mediaIds: [String]?,
spoilerText: String?)
case status(id: String)
case context(id: String)
case favourite(id: String)
@ -12,6 +16,8 @@ public enum Statuses: Endpoint {
public func path() -> String {
switch self {
case .postStatus:
return "statuses"
case .status(let id):
return "statuses/\(id)"
case .context(let id):
@ -33,6 +39,20 @@ public enum Statuses: Endpoint {
public func queryItems() -> [URLQueryItem]? {
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):
return makePaginationParam(sinceId: nil, maxId: maxId)
case let .favouritedBy(_, maxId):

View File

@ -3,25 +3,36 @@ import Accounts
import Env
import DesignSystem
import TextView
import Models
import Network
public struct StatusEditorView: View {
@EnvironmentObject private var client: Client
@EnvironmentObject private var currentAccount: CurrentAccount
@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 {
NavigationStack {
VStack {
accountHeaderView
TextView($viewModel.statusText)
.placeholder("What's on your mind")
.foregroundColor(.clear)
Spacer()
ZStack(alignment: .bottom) {
VStack {
accountHeaderView
TextView($viewModel.statusText)
.placeholder("What's on your mind")
.foregroundColor(.clear)
Spacer()
}
accessoryView
.padding(.bottom, 12)
}
.onAppear {
viewModel.client = client
viewModel.insertReplyTo()
}
.padding(.horizontal, DS.Constants.layoutPadding)
.navigationTitle("New post")
@ -29,7 +40,10 @@ public struct StatusEditorView: View {
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
dismiss()
Task {
_ = await viewModel.postStatus()
dismiss()
}
} label: {
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 DesignSystem
import Models
import Network
@MainActor
class StatusEditorViewModel: ObservableObject {
@ -10,12 +12,37 @@ class StatusEditorViewModel: ObservableObject {
}
}
var client: Client?
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() {
let mutableString = NSMutableAttributedString(attributedString: statusText)
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]()
let hashtagRegex = try! NSRegularExpression(pattern: hashtagPattern, options: [])

View File

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

View File

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