mirror of
https://github.com/mastodon/mastodon-ios.git
synced 2025-02-02 18:36:44 +01:00
commit
c0c795e473
@ -50,13 +50,6 @@ extension APIService {
|
||||
domain: domain,
|
||||
authorization: authorization).singleOutput()
|
||||
|
||||
_ = try await Mastodon.API.Statuses.editHistory(
|
||||
forStatusID: statusID,
|
||||
session: session,
|
||||
domain: domain,
|
||||
authorization: authorization
|
||||
).singleOutput()
|
||||
|
||||
return response
|
||||
}
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ extension Mastodon.API.Media {
|
||||
extension Mastodon.API.Media {
|
||||
|
||||
static func updateMediaEndpointURL(domain: String, attachmentID: Mastodon.Entity.Attachment.ID) -> URL {
|
||||
return Mastodon.API.endpointURL(domain: domain).appendingPathComponent("media").appendingPathComponent(attachmentID)
|
||||
Mastodon.API.endpointURL(domain: domain).appendingPathComponent("media").appendingPathComponent(attachmentID)
|
||||
}
|
||||
|
||||
/// Update attachment
|
||||
|
@ -106,12 +106,41 @@ extension Mastodon.API.Statuses {
|
||||
}
|
||||
|
||||
extension Mastodon.API.Statuses {
|
||||
|
||||
public struct MediaAttributes: Codable {
|
||||
let id: String
|
||||
let description: String?
|
||||
//TODO: Add focus at some point
|
||||
|
||||
public init(id: String, description: String?) {
|
||||
self.id = id
|
||||
self.description = description
|
||||
}
|
||||
}
|
||||
|
||||
public struct Poll: Codable {
|
||||
public let options: [String]?
|
||||
public let expiresIn: Int?
|
||||
public let multipleAnswers: Bool?
|
||||
|
||||
public init(options: [String]?, expiresIn: Int?, multipleAnswers: Bool?) {
|
||||
self.options = options
|
||||
self.expiresIn = expiresIn
|
||||
self.multipleAnswers = multipleAnswers
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case options
|
||||
case expiresIn = "expires_in"
|
||||
case multipleAnswers = "multiple_answers"
|
||||
}
|
||||
}
|
||||
|
||||
public struct EditStatusQuery: Codable, PutQuery {
|
||||
public let status: String?
|
||||
public let mediaIDs: [String]?
|
||||
public let pollOptions: [String]?
|
||||
public let pollExpiresIn: Int?
|
||||
public let pollMultipleAnswers: Bool?
|
||||
public let mediaAttributes: [MediaAttributes]?
|
||||
public let poll: Poll?
|
||||
public let sensitive: Bool?
|
||||
public let spoilerText: String?
|
||||
public let visibility: Mastodon.Entity.Status.Visibility?
|
||||
@ -120,9 +149,8 @@ extension Mastodon.API.Statuses {
|
||||
public init(
|
||||
status: String?,
|
||||
mediaIDs: [String]?,
|
||||
pollOptions: [String]?,
|
||||
pollExpiresIn: Int?,
|
||||
pollMultipleAnswers: Bool?,
|
||||
mediaAttributes: [MediaAttributes]? = nil,
|
||||
poll: Poll?,
|
||||
sensitive: Bool?,
|
||||
spoilerText: String?,
|
||||
visibility: Mastodon.Entity.Status.Visibility?,
|
||||
@ -130,37 +158,23 @@ extension Mastodon.API.Statuses {
|
||||
) {
|
||||
self.status = status
|
||||
self.mediaIDs = mediaIDs
|
||||
self.pollOptions = pollOptions
|
||||
self.pollExpiresIn = pollExpiresIn
|
||||
self.pollMultipleAnswers = pollMultipleAnswers
|
||||
self.mediaAttributes = mediaAttributes
|
||||
self.poll = poll
|
||||
self.sensitive = sensitive
|
||||
self.spoilerText = spoilerText
|
||||
self.visibility = visibility
|
||||
self.language = language
|
||||
}
|
||||
|
||||
var contentType: String? {
|
||||
return Self.multipartContentType()
|
||||
}
|
||||
|
||||
var body: Data? {
|
||||
var data = Data()
|
||||
|
||||
status.flatMap { data.append(Data.multipart(key: "status", value: $0)) }
|
||||
for mediaID in mediaIDs ?? [] {
|
||||
data.append(Data.multipart(key: "media_ids[]", value: mediaID))
|
||||
}
|
||||
for pollOption in pollOptions ?? [] {
|
||||
data.append(Data.multipart(key: "poll[options][]", value: pollOption))
|
||||
}
|
||||
pollExpiresIn.flatMap { data.append(Data.multipart(key: "poll[expires_in]", value: $0)) }
|
||||
sensitive.flatMap { data.append(Data.multipart(key: "sensitive", value: $0)) }
|
||||
spoilerText.flatMap { data.append(Data.multipart(key: "spoiler_text", value: $0)) }
|
||||
visibility.flatMap { data.append(Data.multipart(key: "visibility", value: $0.rawValue)) }
|
||||
language.flatMap { data.append(Data.multipart(key: "language", value: $0)) }
|
||||
|
||||
data.append(Data.multipartEnd())
|
||||
return data
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case status
|
||||
case mediaIDs = "media_ids"
|
||||
case mediaAttributes = "media_attributes"
|
||||
case poll
|
||||
case sensitive
|
||||
case spoilerText = "spoiler_text"
|
||||
case visibility
|
||||
case language
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -120,15 +120,12 @@ extension AttachmentViewModel {
|
||||
}
|
||||
|
||||
let attachment = output.asAttachment
|
||||
|
||||
|
||||
let query = Mastodon.API.Media.UploadMediaQuery(
|
||||
file: attachment,
|
||||
thumbnail: nil,
|
||||
description: {
|
||||
let caption = caption.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
return caption.isEmpty ? nil : caption
|
||||
}(),
|
||||
focus: nil // TODO:
|
||||
description: caption.trimmingCharacters(in: .whitespacesAndNewlines),
|
||||
focus: nil
|
||||
)
|
||||
|
||||
// upload + N * check upload
|
||||
|
@ -47,6 +47,7 @@ final public class AttachmentViewModel: NSObject, ObservableObject, Identifiable
|
||||
public let sizeLimit: SizeLimit
|
||||
@Published var caption = ""
|
||||
@Published public private(set) var isCaptionEditable = true
|
||||
let isEditing: Bool
|
||||
|
||||
// output
|
||||
@Published public private(set) var output: Output?
|
||||
@ -75,15 +76,20 @@ final public class AttachmentViewModel: NSObject, ObservableObject, Identifiable
|
||||
authContext: AuthContext,
|
||||
input: Input,
|
||||
sizeLimit: SizeLimit,
|
||||
delegate: AttachmentViewModelDelegate
|
||||
delegate: AttachmentViewModelDelegate,
|
||||
isEditing: Bool = false,
|
||||
caption: String? = nil
|
||||
) {
|
||||
self.api = api
|
||||
self.authContext = authContext
|
||||
self.input = input
|
||||
self.sizeLimit = sizeLimit
|
||||
self.delegate = delegate
|
||||
self.isEditing = isEditing
|
||||
|
||||
self.caption = caption ?? ""
|
||||
|
||||
super.init()
|
||||
// end init
|
||||
|
||||
Timer.publish(every: 1.0 / 60.0, on: .main, in: .common) // 60 FPS
|
||||
.autoconnect()
|
||||
@ -134,7 +140,9 @@ final public class AttachmentViewModel: NSObject, ObservableObject, Identifiable
|
||||
|
||||
switch input {
|
||||
case .mastodonAssetUrl:
|
||||
self.isCaptionEditable = false
|
||||
if self.isEditing == false {
|
||||
self.isCaptionEditable = false
|
||||
}
|
||||
self.uploadState = .finish
|
||||
self.output = output
|
||||
self.uploadResult = .exists
|
||||
@ -258,7 +266,7 @@ extension AttachmentViewModel {
|
||||
public enum Input: Hashable {
|
||||
case image(UIImage)
|
||||
case url(URL)
|
||||
case mastodonAssetUrl(URL, String)
|
||||
case mastodonAssetUrl(url: URL, attachmentId: String)
|
||||
case pickerResult(PHPickerResult)
|
||||
case itemProvider(NSItemProvider)
|
||||
}
|
||||
@ -321,4 +329,5 @@ extension AttachmentViewModel {
|
||||
func update(uploadResult: UploadResult) {
|
||||
self.uploadResult = uploadResult
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -265,14 +265,16 @@ public final class ComposeContentViewModel: NSObject, ObservableObject {
|
||||
self.isVisibilityButtonEnabled = false
|
||||
self.attachmentViewModels = status.entity.mastodonAttachments.compactMap {
|
||||
guard let assetURL = $0.assetURL, let url = URL(string: assetURL) else { return nil }
|
||||
|
||||
let attachmentViewModel = AttachmentViewModel(
|
||||
api: context.apiService,
|
||||
authContext: authContext,
|
||||
input: .mastodonAssetUrl(url, $0.id),
|
||||
input: .mastodonAssetUrl(url: url, attachmentId: $0.id),
|
||||
sizeLimit: sizeLimit,
|
||||
delegate: self
|
||||
delegate: self,
|
||||
isEditing: true,
|
||||
caption: $0.altDescription
|
||||
)
|
||||
attachmentViewModel.caption = $0.altDescription ?? ""
|
||||
return attachmentViewModel
|
||||
}
|
||||
}
|
||||
|
@ -115,8 +115,8 @@ extension MastodonEditStatusPublisher: StatusPublisher {
|
||||
guard case let AttachmentViewModel.Input.mastodonAssetUrl(_, attachmentId) = attachmentViewModel.input else {
|
||||
throw AppError.badRequest
|
||||
}
|
||||
|
||||
attachmentIDs.append(attachmentId)
|
||||
break
|
||||
case let .uploadedMastodonAttachment(attachment):
|
||||
attachmentIDs.append(attachment.id)
|
||||
|
||||
@ -157,12 +157,21 @@ extension MastodonEditStatusPublisher: StatusPublisher {
|
||||
return self.pollExpireConfigurationOption.seconds
|
||||
}()
|
||||
|
||||
let poll = Mastodon.API.Statuses.Poll(options: pollOptions, expiresIn: pollExpiresIn, multipleAnswers: self.pollMultipleConfigurationOption)
|
||||
|
||||
let mediaAttributes: [Mastodon.API.Statuses.MediaAttributes] = attachmentViewModels.compactMap {
|
||||
if case let .mastodonAssetUrl(url: _, attachmentId: attachmentId) = $0.input {
|
||||
return Mastodon.API.Statuses.MediaAttributes(id: attachmentId, description: $0.caption)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
let query = Mastodon.API.Statuses.EditStatusQuery(
|
||||
status: content,
|
||||
mediaIDs: attachmentIDs.isEmpty ? nil : attachmentIDs,
|
||||
pollOptions: pollOptions,
|
||||
pollExpiresIn: pollExpiresIn,
|
||||
pollMultipleAnswers: pollMultipleConfigurationOption,
|
||||
mediaAttributes: mediaAttributes,
|
||||
poll: poll,
|
||||
sensitive: isMediaSensitive,
|
||||
spoilerText: isContentWarningComposing ? contentWarning : nil,
|
||||
visibility: visibility,
|
||||
|
@ -124,17 +124,14 @@ extension MastodonStatusPublisher: StatusPublisher {
|
||||
break
|
||||
case let .uploadedMastodonAttachment(attachment):
|
||||
attachmentIDs.append(attachment.id)
|
||||
|
||||
let caption = attachmentViewModel.caption
|
||||
guard !caption.isEmpty else { continue }
|
||||
|
||||
|
||||
_ = try await api.updateMedia(
|
||||
domain: authContext.mastodonAuthenticationBox.domain,
|
||||
attachmentID: attachment.id,
|
||||
query: .init(
|
||||
file: nil,
|
||||
thumbnail: nil,
|
||||
description: caption,
|
||||
description: attachmentViewModel.caption,
|
||||
focus: nil
|
||||
),
|
||||
mastodonAuthenticationBox: authContext.mastodonAuthenticationBox
|
||||
|
Loading…
x
Reference in New Issue
Block a user