mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2025-01-03 12:58:50 +00:00
Very basic status post
This commit is contained in:
parent
e569bb1d74
commit
8df70043cb
8 changed files with 95 additions and 25 deletions
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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: [])
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue