mirror of
https://github.com/metabolist/metatext.git
synced 2024-11-29 03:21:02 +00:00
Delete and redraft
This commit is contained in:
parent
96d96bd899
commit
88c3fedd93
15 changed files with 159 additions and 33 deletions
|
@ -221,6 +221,12 @@ public extension ContentDatabase {
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func delete(id: Status.Id) -> AnyPublisher<Never, Error> {
|
||||||
|
databaseWriter.writePublisher(updates: StatusRecord.filter(StatusRecord.Columns.id == id).deleteAll)
|
||||||
|
.ignoreOutput()
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
func unfollow(id: Account.Id) -> AnyPublisher<Never, Error> {
|
func unfollow(id: Account.Id) -> AnyPublisher<Never, Error> {
|
||||||
databaseWriter.writePublisher {
|
databaseWriter.writePublisher {
|
||||||
let statusIds = try Status.Id.fetchAll(
|
let statusIds = try Status.Id.fetchAll(
|
||||||
|
|
|
@ -156,6 +156,8 @@
|
||||||
"share-extension-error.no-account-found" = "No account found";
|
"share-extension-error.no-account-found" = "No account found";
|
||||||
"status.bookmark" = "Bookmark";
|
"status.bookmark" = "Bookmark";
|
||||||
"status.content-warning-abbreviation" = "CW";
|
"status.content-warning-abbreviation" = "CW";
|
||||||
|
"status.delete" = "Delete";
|
||||||
|
"status.delete-and-redraft" = "Delete & re-draft";
|
||||||
"status.mute" = "Mute conversation";
|
"status.mute" = "Mute conversation";
|
||||||
"status.pin" = "Pin on profile";
|
"status.pin" = "Pin on profile";
|
||||||
"status.pinned-post" = "Pinned post";
|
"status.pinned-post" = "Pinned post";
|
||||||
|
|
|
@ -17,7 +17,7 @@ public final class Status: Codable, Identifiable {
|
||||||
public let uri: String
|
public let uri: String
|
||||||
public let createdAt: Date
|
public let createdAt: Date
|
||||||
public let account: Account
|
public let account: Account
|
||||||
public let content: HTML
|
@DecodableDefault.EmptyHTML public private(set) var content: HTML
|
||||||
public let visibility: Visibility
|
public let visibility: Visibility
|
||||||
public let sensitive: Bool
|
public let sensitive: Bool
|
||||||
public let spoilerText: String
|
public let spoilerText: String
|
||||||
|
@ -77,7 +77,6 @@ public final class Status: Codable, Identifiable {
|
||||||
self.uri = uri
|
self.uri = uri
|
||||||
self.createdAt = createdAt
|
self.createdAt = createdAt
|
||||||
self.account = account
|
self.account = account
|
||||||
self.content = content
|
|
||||||
self.visibility = visibility
|
self.visibility = visibility
|
||||||
self.sensitive = sensitive
|
self.sensitive = sensitive
|
||||||
self.spoilerText = spoilerText
|
self.spoilerText = spoilerText
|
||||||
|
@ -98,6 +97,7 @@ public final class Status: Codable, Identifiable {
|
||||||
self.text = text
|
self.text = text
|
||||||
self.pinned = pinned
|
self.pinned = pinned
|
||||||
self.repliesCount = repliesCount
|
self.repliesCount = repliesCount
|
||||||
|
self.content = content
|
||||||
self.favourited = favourited
|
self.favourited = favourited
|
||||||
self.reblogged = reblogged
|
self.reblogged = reblogged
|
||||||
self.muted = muted
|
self.muted = muted
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
// Thank you https://www.swiftbysundell.com/tips/default-decoding-values/
|
|
||||||
|
|
||||||
public protocol DecodableDefaultSource {
|
public protocol DecodableDefaultSource {
|
||||||
associatedtype Value: Decodable
|
associatedtype Value: Decodable
|
||||||
static var defaultValue: Value { get }
|
static var defaultValue: Value { get }
|
||||||
|
@ -40,6 +38,10 @@ public extension DecodableDefault {
|
||||||
public static var defaultValue: String { "" }
|
public static var defaultValue: String { "" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum EmptyHTML: Source {
|
||||||
|
public static var defaultValue: HTML { HTML(raw: "", attributed: NSAttributedString(string: "")) }
|
||||||
|
}
|
||||||
|
|
||||||
public enum EmptyList<T: List>: Source {
|
public enum EmptyList<T: List>: Source {
|
||||||
public static var defaultValue: T { [] }
|
public static var defaultValue: T { [] }
|
||||||
}
|
}
|
||||||
|
@ -67,6 +69,7 @@ public extension DecodableDefault {
|
||||||
typealias True = Wrapper<Sources.True>
|
typealias True = Wrapper<Sources.True>
|
||||||
typealias False = Wrapper<Sources.False>
|
typealias False = Wrapper<Sources.False>
|
||||||
typealias EmptyString = Wrapper<Sources.EmptyString>
|
typealias EmptyString = Wrapper<Sources.EmptyString>
|
||||||
|
typealias EmptyHTML = Wrapper<Sources.EmptyHTML>
|
||||||
typealias EmptyList<T: List> = Wrapper<Sources.EmptyList<T>>
|
typealias EmptyList<T: List> = Wrapper<Sources.EmptyList<T>>
|
||||||
typealias EmptyMap<T: Map> = Wrapper<Sources.EmptyMap<T>>
|
typealias EmptyMap<T: Map> = Wrapper<Sources.EmptyMap<T>>
|
||||||
typealias Zero = Wrapper<Sources.Zero>
|
typealias Zero = Wrapper<Sources.Zero>
|
||||||
|
|
|
@ -16,6 +16,7 @@ public enum StatusEndpoint {
|
||||||
case unpin(id: Status.Id)
|
case unpin(id: Status.Id)
|
||||||
case mute(id: Status.Id)
|
case mute(id: Status.Id)
|
||||||
case unmute(id: Status.Id)
|
case unmute(id: Status.Id)
|
||||||
|
case delete(id: Status.Id)
|
||||||
case post(Components)
|
case post(Components)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +101,7 @@ extension StatusEndpoint: Endpoint {
|
||||||
|
|
||||||
public var pathComponentsInContext: [String] {
|
public var pathComponentsInContext: [String] {
|
||||||
switch self {
|
switch self {
|
||||||
case let .status(id):
|
case let .status(id), let .delete(id):
|
||||||
return [id]
|
return [id]
|
||||||
case let .reblog(id):
|
case let .reblog(id):
|
||||||
return [id, "reblog"]
|
return [id, "reblog"]
|
||||||
|
@ -140,6 +141,8 @@ extension StatusEndpoint: Endpoint {
|
||||||
switch self {
|
switch self {
|
||||||
case .status:
|
case .status:
|
||||||
return .get
|
return .get
|
||||||
|
case .delete:
|
||||||
|
return .delete
|
||||||
default:
|
default:
|
||||||
return .post
|
return .post
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,34 @@ public extension StatusService {
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func delete() -> AnyPublisher<Status, Error> {
|
||||||
|
mastodonAPIClient.request(StatusEndpoint.delete(id: status.displayStatus.id))
|
||||||
|
.flatMap { status in contentDatabase.delete(id: status.id).collect().map { _ in status } }
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteAndRedraft() -> AnyPublisher<(Status, Self?), Error> {
|
||||||
|
let inReplyToPublisher: AnyPublisher<Self?, Never>
|
||||||
|
|
||||||
|
if let inReplyToId = status.displayStatus.inReplyToId {
|
||||||
|
inReplyToPublisher = mastodonAPIClient.request(StatusEndpoint.status(id: inReplyToId))
|
||||||
|
.map {
|
||||||
|
Self(status: $0,
|
||||||
|
mastodonAPIClient: mastodonAPIClient,
|
||||||
|
contentDatabase: contentDatabase) as Self?
|
||||||
|
}
|
||||||
|
.replaceError(with: nil)
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
} else {
|
||||||
|
inReplyToPublisher = Just(nil).eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
return mastodonAPIClient.request(StatusEndpoint.delete(id: status.displayStatus.id))
|
||||||
|
.flatMap { status in contentDatabase.delete(id: status.id).collect().map { _ in status } }
|
||||||
|
.zip(inReplyToPublisher.setFailureType(to: Error.self))
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
func rebloggedByService() -> AccountListService {
|
func rebloggedByService() -> AccountListService {
|
||||||
AccountListService(
|
AccountListService(
|
||||||
endpoint: .rebloggedBy(id: status.id),
|
endpoint: .rebloggedBy(id: status.id),
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import AVKit
|
import AVKit
|
||||||
import Combine
|
import Combine
|
||||||
|
import Mastodon
|
||||||
import SafariServices
|
import SafariServices
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import ViewModels
|
import ViewModels
|
||||||
|
@ -248,6 +249,7 @@ private extension TableViewController {
|
||||||
|
|
||||||
viewModel.alertItems
|
viewModel.alertItems
|
||||||
.compactMap { $0 }
|
.compactMap { $0 }
|
||||||
|
.handleEvents(receiveOutput: { print($0.error) })
|
||||||
.sink { [weak self] in self?.present(alertItem: $0) }
|
.sink { [weak self] in self?.present(alertItem: $0) }
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
@ -303,8 +305,8 @@ private extension TableViewController {
|
||||||
handle(navigation: navigation)
|
handle(navigation: navigation)
|
||||||
case let .attachment(attachmentViewModel, statusViewModel):
|
case let .attachment(attachmentViewModel, statusViewModel):
|
||||||
present(attachmentViewModel: attachmentViewModel, statusViewModel: statusViewModel)
|
present(attachmentViewModel: attachmentViewModel, statusViewModel: statusViewModel)
|
||||||
case let .reply(statusViewModel):
|
case let .compose(inReplyToViewModel, redraft):
|
||||||
reply(statusViewModel: statusViewModel)
|
compose(inReplyToViewModel: inReplyToViewModel, redraft: redraft)
|
||||||
case let .report(reportViewModel):
|
case let .report(reportViewModel):
|
||||||
report(reportViewModel: reportViewModel)
|
report(reportViewModel: reportViewModel)
|
||||||
}
|
}
|
||||||
|
@ -374,10 +376,11 @@ private extension TableViewController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func reply(statusViewModel: StatusViewModel) {
|
func compose(inReplyToViewModel: StatusViewModel?, redraft: Status?) {
|
||||||
let newStatusViewModel = rootViewModel.newStatusViewModel(
|
let newStatusViewModel = rootViewModel.newStatusViewModel(
|
||||||
identification: identification,
|
identification: identification,
|
||||||
inReplyTo: statusViewModel)
|
inReplyTo: inReplyToViewModel,
|
||||||
|
redraft: redraft)
|
||||||
let newStatusViewController = UIHostingController(rootView: NewStatusView { newStatusViewModel })
|
let newStatusViewController = UIHostingController(rootView: NewStatusView { newStatusViewModel })
|
||||||
let navigationController = UINavigationController(rootViewController: newStatusViewController)
|
let navigationController = UINavigationController(rootViewController: newStatusViewController)
|
||||||
|
|
||||||
|
|
|
@ -8,16 +8,15 @@ import ServiceLayer
|
||||||
public final class CompositionViewModel: AttachmentsRenderingViewModel, ObservableObject, Identifiable {
|
public final class CompositionViewModel: AttachmentsRenderingViewModel, ObservableObject, Identifiable {
|
||||||
public let id = Id()
|
public let id = Id()
|
||||||
public var isPosted = false
|
public var isPosted = false
|
||||||
@Published public var text = ""
|
@Published public var text: String
|
||||||
@Published public var contentWarning = ""
|
@Published public var contentWarning: String
|
||||||
@Published public var displayContentWarning = false
|
@Published public var displayContentWarning: Bool
|
||||||
@Published public var sensitive = false
|
@Published public var sensitive: Bool
|
||||||
@Published public var displayPoll = false
|
@Published public var displayPoll: Bool
|
||||||
@Published public var pollMultipleChoice = false
|
@Published public var pollMultipleChoice: Bool
|
||||||
@Published public var pollHideTotals = false
|
|
||||||
@Published public var pollExpiresIn = PollExpiry.oneDay
|
@Published public var pollExpiresIn = PollExpiry.oneDay
|
||||||
@Published public private(set) var pollOptions = [PollOption(text: ""), PollOption(text: "")]
|
@Published public private(set) var pollOptions: [PollOption]
|
||||||
@Published public private(set) var attachmentViewModels = [AttachmentViewModel]()
|
@Published public private(set) var attachmentViewModels: [AttachmentViewModel]
|
||||||
@Published public private(set) var attachmentUpload: AttachmentUpload?
|
@Published public private(set) var attachmentUpload: AttachmentUpload?
|
||||||
@Published public private(set) var isPostable = false
|
@Published public private(set) var isPostable = false
|
||||||
@Published public private(set) var canAddAttachment = true
|
@Published public private(set) var canAddAttachment = true
|
||||||
|
@ -28,8 +27,24 @@ public final class CompositionViewModel: AttachmentsRenderingViewModel, Observab
|
||||||
private let eventsSubject: PassthroughSubject<Event, Never>
|
private let eventsSubject: PassthroughSubject<Event, Never>
|
||||||
private var attachmentUploadCancellable: AnyCancellable?
|
private var attachmentUploadCancellable: AnyCancellable?
|
||||||
|
|
||||||
init(eventsSubject: PassthroughSubject<Event, Never>) {
|
init(eventsSubject: PassthroughSubject<Event, Never>,
|
||||||
|
redraft: (status: Status, identification: Identification)? = nil) {
|
||||||
self.eventsSubject = eventsSubject
|
self.eventsSubject = eventsSubject
|
||||||
|
text = redraft?.status.text ?? ""
|
||||||
|
contentWarning = redraft?.status.spoilerText ?? ""
|
||||||
|
displayContentWarning = !(redraft?.status.spoilerText.isEmpty ?? true)
|
||||||
|
sensitive = redraft?.status.sensitive ?? false
|
||||||
|
displayPoll = redraft?.status.poll != nil
|
||||||
|
pollMultipleChoice = redraft?.status.poll?.multiple ?? false
|
||||||
|
pollOptions = redraft?.status.poll?.options.map { PollOption(text: $0.title) }
|
||||||
|
?? [PollOption(text: ""), PollOption(text: "")]
|
||||||
|
if let redraft = redraft {
|
||||||
|
attachmentViewModels = redraft.status.mediaAttachments.map {
|
||||||
|
AttachmentViewModel(attachment: $0, identification: redraft.identification)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
attachmentViewModels = [AttachmentViewModel]()
|
||||||
|
}
|
||||||
|
|
||||||
$text.map { !$0.isEmpty }
|
$text.map { !$0.isEmpty }
|
||||||
.removeDuplicates()
|
.removeDuplicates()
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
// Copyright © 2020 Metabolist. All rights reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import Mastodon
|
||||||
import ServiceLayer
|
import ServiceLayer
|
||||||
|
|
||||||
public enum CollectionItemEvent {
|
public enum CollectionItemEvent {
|
||||||
case ignorableOutput
|
case ignorableOutput
|
||||||
case navigation(Navigation)
|
case navigation(Navigation)
|
||||||
case attachment(AttachmentViewModel, StatusViewModel)
|
case attachment(AttachmentViewModel, StatusViewModel)
|
||||||
case reply(StatusViewModel)
|
case compose(inReplyTo: StatusViewModel?, redraft: Status?)
|
||||||
case report(ReportViewModel)
|
case report(ReportViewModel)
|
||||||
case share(URL)
|
case share(URL)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,12 +26,24 @@ public final class NewStatusViewModel: ObservableObject {
|
||||||
public init(allIdentitiesService: AllIdentitiesService,
|
public init(allIdentitiesService: AllIdentitiesService,
|
||||||
identification: Identification,
|
identification: Identification,
|
||||||
environment: AppEnvironment,
|
environment: AppEnvironment,
|
||||||
inReplyTo: StatusViewModel?) {
|
inReplyTo: StatusViewModel?,
|
||||||
|
redraft: Status?) {
|
||||||
self.allIdentitiesService = allIdentitiesService
|
self.allIdentitiesService = allIdentitiesService
|
||||||
self.identification = identification
|
self.identification = identification
|
||||||
self.environment = environment
|
self.environment = environment
|
||||||
inReplyToViewModel = inReplyTo
|
inReplyToViewModel = inReplyTo
|
||||||
compositionViewModels = [CompositionViewModel(eventsSubject: compositionEventsSubject)]
|
|
||||||
|
let redraftAndIdentification: (status: Status, identification: Identification)?
|
||||||
|
|
||||||
|
if let redraft = redraft {
|
||||||
|
redraftAndIdentification = (status: redraft, identification: identification)
|
||||||
|
} else {
|
||||||
|
redraftAndIdentification = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
compositionViewModels = [CompositionViewModel(
|
||||||
|
eventsSubject: compositionEventsSubject,
|
||||||
|
redraft: redraftAndIdentification)]
|
||||||
events = eventsSubject.eraseToAnyPublisher()
|
events = eventsSubject.eraseToAnyPublisher()
|
||||||
visibility = identification.identity.preferences.postingDefaultVisibility
|
visibility = identification.identity.preferences.postingDefaultVisibility
|
||||||
allIdentitiesService.authenticatedIdentitiesPublisher()
|
allIdentitiesService.authenticatedIdentitiesPublisher()
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import Mastodon
|
||||||
import ServiceLayer
|
import ServiceLayer
|
||||||
|
|
||||||
public final class RootViewModel: ObservableObject {
|
public final class RootViewModel: ObservableObject {
|
||||||
|
@ -58,12 +59,16 @@ public extension RootViewModel {
|
||||||
instanceURLService: InstanceURLService(environment: environment))
|
instanceURLService: InstanceURLService(environment: environment))
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStatusViewModel(identification: Identification, inReplyTo: StatusViewModel? = nil) -> NewStatusViewModel {
|
func newStatusViewModel(
|
||||||
|
identification: Identification,
|
||||||
|
inReplyTo: StatusViewModel? = nil,
|
||||||
|
redraft: Status? = nil) -> NewStatusViewModel {
|
||||||
NewStatusViewModel(
|
NewStatusViewModel(
|
||||||
allIdentitiesService: allIdentitiesService,
|
allIdentitiesService: allIdentitiesService,
|
||||||
identification: identification,
|
identification: identification,
|
||||||
environment: environment,
|
environment: environment,
|
||||||
inReplyTo: inReplyTo)
|
inReplyTo: inReplyTo,
|
||||||
|
redraft: redraft)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ public extension ShareExtensionNavigationViewModel {
|
||||||
allIdentitiesService: allIdentitiesService,
|
allIdentitiesService: allIdentitiesService,
|
||||||
identification: identification,
|
identification: identification,
|
||||||
environment: environment,
|
environment: environment,
|
||||||
inReplyTo: nil)
|
inReplyTo: nil,
|
||||||
|
redraft: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,7 +213,10 @@ public extension StatusViewModel {
|
||||||
|
|
||||||
replyViewModel.configuration = configuration.reply()
|
replyViewModel.configuration = configuration.reply()
|
||||||
|
|
||||||
eventsSubject.send(Just(.reply(replyViewModel)).setFailureType(to: Error.self).eraseToAnyPublisher())
|
eventsSubject.send(
|
||||||
|
Just(.compose(inReplyTo: replyViewModel, redraft: nil))
|
||||||
|
.setFailureType(to: Error.self)
|
||||||
|
.eraseToAnyPublisher())
|
||||||
}
|
}
|
||||||
|
|
||||||
func toggleReblogged() {
|
func toggleReblogged() {
|
||||||
|
@ -251,6 +254,35 @@ public extension StatusViewModel {
|
||||||
.eraseToAnyPublisher())
|
.eraseToAnyPublisher())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func delete() {
|
||||||
|
eventsSubject.send(
|
||||||
|
statusService.delete()
|
||||||
|
.map { _ in .ignorableOutput }
|
||||||
|
.eraseToAnyPublisher())
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteAndRedraft() {
|
||||||
|
let identification = self.identification
|
||||||
|
|
||||||
|
eventsSubject.send(
|
||||||
|
statusService.deleteAndRedraft()
|
||||||
|
.map { redraft, inReplyToStatusService in
|
||||||
|
let inReplyToViewModel: StatusViewModel?
|
||||||
|
|
||||||
|
if let inReplyToStatusService = inReplyToStatusService {
|
||||||
|
inReplyToViewModel = Self(
|
||||||
|
statusService: inReplyToStatusService,
|
||||||
|
identification: identification)
|
||||||
|
inReplyToViewModel?.configuration = CollectionItem.StatusConfiguration.default.reply()
|
||||||
|
} else {
|
||||||
|
inReplyToViewModel = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return .compose(inReplyTo: inReplyToViewModel, redraft: redraft)
|
||||||
|
}
|
||||||
|
.eraseToAnyPublisher())
|
||||||
|
}
|
||||||
|
|
||||||
func attachmentSelected(viewModel: AttachmentViewModel) {
|
func attachmentSelected(viewModel: AttachmentViewModel) {
|
||||||
eventsSubject.send(Just(.attachment(viewModel, self)).setFailureType(to: Error.self).eraseToAnyPublisher())
|
eventsSubject.send(Just(.attachment(viewModel, self)).setFailureType(to: Error.self).eraseToAnyPublisher())
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ private extension CompositionPollOptionView {
|
||||||
UIAction { [weak self] _ in
|
UIAction { [weak self] _ in
|
||||||
self?.option.text = textField.text ?? "" },
|
self?.option.text = textField.text ?? "" },
|
||||||
for: .editingChanged)
|
for: .editingChanged)
|
||||||
|
textField.text = option.text
|
||||||
|
|
||||||
stackView.addArrangedSubview(remainingCharactersLabel)
|
stackView.addArrangedSubview(remainingCharactersLabel)
|
||||||
remainingCharactersLabel.adjustsFontForContentSizeCategory = true
|
remainingCharactersLabel.adjustsFontForContentSizeCategory = true
|
||||||
|
|
|
@ -419,13 +419,27 @@ private extension StatusView {
|
||||||
}
|
}
|
||||||
|
|
||||||
if viewModel.isMine {
|
if viewModel.isMine {
|
||||||
menuItems.append(UIAction(
|
menuItems += [
|
||||||
|
UIAction(
|
||||||
title: viewModel.muted
|
title: viewModel.muted
|
||||||
? NSLocalizedString("status.unmute", comment: "")
|
? NSLocalizedString("status.unmute", comment: "")
|
||||||
: NSLocalizedString("status.mute", comment: ""),
|
: NSLocalizedString("status.mute", comment: ""),
|
||||||
image: UIImage(systemName: viewModel.muted ? "speaker" : "speaker.slash")) { _ in
|
image: UIImage(systemName: viewModel.muted ? "speaker" : "speaker.slash")) { _ in
|
||||||
viewModel.toggleMuted()
|
viewModel.toggleMuted()
|
||||||
})
|
},
|
||||||
|
UIAction(
|
||||||
|
title: NSLocalizedString("status.delete", comment: ""),
|
||||||
|
image: UIImage(systemName: "trash"),
|
||||||
|
attributes: .destructive) { _ in
|
||||||
|
viewModel.delete()
|
||||||
|
},
|
||||||
|
UIAction(
|
||||||
|
title: NSLocalizedString("status.delete-and-redraft", comment: ""),
|
||||||
|
image: UIImage(systemName: "trash.circle"),
|
||||||
|
attributes: .destructive) { _ in
|
||||||
|
viewModel.deleteAndRedraft()
|
||||||
|
}
|
||||||
|
]
|
||||||
} else {
|
} else {
|
||||||
menuItems.append(UIAction(
|
menuItems.append(UIAction(
|
||||||
title: NSLocalizedString("report", comment: ""),
|
title: NSLocalizedString("report", comment: ""),
|
||||||
|
|
Loading…
Reference in a new issue