forked from shadowfacts/Tusker
Add delete status action
This commit is contained in:
parent
5f19adf2d0
commit
db1bbf7148
|
@ -64,8 +64,8 @@ public final class Status: StatusProtocol, Decodable {
|
|||
return request
|
||||
}
|
||||
|
||||
public static func delete(_ status: Status) -> Request<Empty> {
|
||||
return Request<Empty>(method: .delete, path: "/api/v1/statuses/\(status.id)")
|
||||
public static func delete(_ statusID: String) -> Request<Empty> {
|
||||
return Request<Empty>(method: .delete, path: "/api/v1/statuses/\(statusID)")
|
||||
}
|
||||
|
||||
public static func reblog(_ statusID: String, visibility: Visibility? = nil) -> Request<Status> {
|
||||
|
|
|
@ -152,6 +152,7 @@
|
|||
D65B4B5E2973040D00DABDFB /* ReportAddStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65B4B5D2973040D00DABDFB /* ReportAddStatusView.swift */; };
|
||||
D65B4B6229771A3F00DABDFB /* FetchStatusService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65B4B6129771A3F00DABDFB /* FetchStatusService.swift */; };
|
||||
D65B4B6429771EFF00DABDFB /* ConversationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65B4B6329771EFF00DABDFB /* ConversationViewController.swift */; };
|
||||
D65B4B6629773AE600DABDFB /* DeleteStatusService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65B4B6529773AE600DABDFB /* DeleteStatusService.swift */; };
|
||||
D65C6BF525478A9C00A6E89C /* BackgroundableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65C6BF425478A9C00A6E89C /* BackgroundableViewController.swift */; };
|
||||
D65F613423AEAB6600F3CFD3 /* OnboardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65F613323AEAB6600F3CFD3 /* OnboardingTests.swift */; };
|
||||
D6620ACE2511A0ED00312CA0 /* StatusStateResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6620ACD2511A0ED00312CA0 /* StatusStateResolver.swift */; };
|
||||
|
@ -541,6 +542,7 @@
|
|||
D65B4B5D2973040D00DABDFB /* ReportAddStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportAddStatusView.swift; sourceTree = "<group>"; };
|
||||
D65B4B6129771A3F00DABDFB /* FetchStatusService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchStatusService.swift; sourceTree = "<group>"; };
|
||||
D65B4B6329771EFF00DABDFB /* ConversationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationViewController.swift; sourceTree = "<group>"; };
|
||||
D65B4B6529773AE600DABDFB /* DeleteStatusService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteStatusService.swift; sourceTree = "<group>"; };
|
||||
D65C6BF425478A9C00A6E89C /* BackgroundableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundableViewController.swift; sourceTree = "<group>"; };
|
||||
D65F612D23AE990C00F3CFD3 /* Embassy.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Embassy.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D65F613023AE99E000F3CFD3 /* Ambassador.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Ambassador.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -1612,6 +1614,7 @@
|
|||
D61F75B2293BD89C00C0B37F /* UpdateFilterService.swift */,
|
||||
D61F75B4293BD97400C0B37F /* DeleteFilterService.swift */,
|
||||
D65B4B6129771A3F00DABDFB /* FetchStatusService.swift */,
|
||||
D65B4B6529773AE600DABDFB /* DeleteStatusService.swift */,
|
||||
);
|
||||
path = API;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1985,6 +1988,7 @@
|
|||
D6114E0D27F7FEB30080E273 /* TrendingStatusesViewController.swift in Sources */,
|
||||
D6BC9DDA232D8BE5002CA326 /* SearchResultsViewController.swift in Sources */,
|
||||
D61ABEF628EE74D400B29151 /* StatusCollectionViewCell.swift in Sources */,
|
||||
D65B4B6629773AE600DABDFB /* DeleteStatusService.swift in Sources */,
|
||||
D61DC84628F498F200B82C6E /* Logging.swift in Sources */,
|
||||
D6B17255254F88B800128392 /* OppositeCollapseKeywordsView.swift in Sources */,
|
||||
D6A00B1D26379FC900316AD4 /* PollOptionsView.swift in Sources */,
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// DeleteStatusService.swift
|
||||
// Tusker
|
||||
//
|
||||
// Created by Shadowfacts on 1/17/23.
|
||||
// Copyright © 2023 Shadowfacts. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Pachyderm
|
||||
|
||||
@MainActor
|
||||
class DeleteStatusService {
|
||||
let status: StatusMO
|
||||
let mastodonController: MastodonController
|
||||
let presenter: any TuskerNavigationDelegate
|
||||
|
||||
init(status: StatusMO, mastodonController: MastodonController, presenter: any TuskerNavigationDelegate) {
|
||||
self.status = status
|
||||
self.mastodonController = mastodonController
|
||||
self.presenter = presenter
|
||||
}
|
||||
|
||||
func run() async {
|
||||
do {
|
||||
let req = Status.delete(status.id)
|
||||
let _ = try await mastodonController.run(req)
|
||||
|
||||
// we deliberately don't remove the status from the cache because there are almost certainly places where it'll still be fetched again
|
||||
|
||||
var reblogIDs = [String]()
|
||||
let reblogsReq = StatusMO.fetchRequest()
|
||||
reblogsReq.predicate = NSPredicate(format: "reblog = %@", status)
|
||||
if let reblogs = try? mastodonController.persistentContainer.viewContext.fetch(reblogsReq) {
|
||||
reblogIDs = reblogs.map(\.id)
|
||||
}
|
||||
|
||||
NotificationCenter.default.post(name: .statusDeleted, object: nil, userInfo: [
|
||||
"accountID": mastodonController.accountInfo!.id,
|
||||
"statusIDs": [status.id] + reblogIDs,
|
||||
])
|
||||
} catch {
|
||||
let message: String
|
||||
if let error = error as? Client.Error {
|
||||
message = error.localizedDescription
|
||||
} else {
|
||||
message = error.localizedDescription
|
||||
}
|
||||
let alert = UIAlertController(title: "Error Deleting Post", message: message, preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
|
||||
alert.addAction(UIAlertAction(title: "Retry", style: .default, handler: { _ in
|
||||
Task {
|
||||
await self.run()
|
||||
}
|
||||
}))
|
||||
presenter.present(alert, animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Foundation.Notification.Name {
|
||||
static let statusDeleted = Foundation.Notification.Name("statusDeleted")
|
||||
}
|
|
@ -48,6 +48,8 @@ class BookmarksTableViewController: EnhancedTableViewController {
|
|||
tableView.prefetchDataSource = self
|
||||
|
||||
userActivity = UserActivityManager.bookmarksActivity()
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handleStatusDeleted), name: .statusDeleted, object: nil)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
|
@ -152,6 +154,21 @@ class BookmarksTableViewController: EnhancedTableViewController {
|
|||
return config
|
||||
}
|
||||
|
||||
@objc private func handleStatusDeleted(_ notification: Foundation.Notification) {
|
||||
guard let userInfo = notification.userInfo,
|
||||
let accountID = mastodonController.accountInfo?.id,
|
||||
userInfo["accountID"] as? String == accountID,
|
||||
let statusIDs = userInfo["statusIDs"] as? [String] else {
|
||||
return
|
||||
}
|
||||
let indicesToDelete = statusIDs
|
||||
.compactMap { id in
|
||||
self.statuses.firstIndex(where: { $0.id == id })
|
||||
}
|
||||
self.statuses.remove(atOffsets: IndexSet(indicesToDelete))
|
||||
self.tableView.deleteRows(at: indicesToDelete.map { IndexPath(row: $0, section: 0) }, with: .automatic)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension BookmarksTableViewController: TuskerNavigationDelegate {
|
||||
|
|
|
@ -134,7 +134,9 @@ class ConversationTableViewController: EnhancedTableViewController {
|
|||
|
||||
let mainStatusItem = Item.status(id: mainStatusID, state: mainStatusState)
|
||||
|
||||
var snapshot = self.dataSource.snapshot()
|
||||
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
||||
snapshot.appendSections([.statuses])
|
||||
snapshot.appendItems([mainStatusItem], toSection: .statuses)
|
||||
snapshot.insertItems(parentIDs.map { .status(id: $0, state: .unknown) }, beforeItem: mainStatusItem)
|
||||
|
||||
// fetch all descendant status managed objects
|
||||
|
|
|
@ -91,6 +91,8 @@ class ConversationViewController: UIViewController {
|
|||
let appearance = UINavigationBarAppearance()
|
||||
appearance.configureWithDefaultBackground()
|
||||
navigationItem.scrollEdgeAppearance = appearance
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handleStatusDeleted), name: .statusDeleted, object: nil)
|
||||
}
|
||||
|
||||
private func updateVisibilityBarButtonItem() {
|
||||
|
@ -113,6 +115,23 @@ class ConversationViewController: UIViewController {
|
|||
}
|
||||
}
|
||||
|
||||
@objc private func handleStatusDeleted(_ notification: Foundation.Notification) {
|
||||
guard let userInfo = notification.userInfo,
|
||||
let accountID = mastodonController.accountInfo?.id,
|
||||
userInfo["accountID"] as? String == accountID,
|
||||
let statusIDs = userInfo["statusIDs"] as? [String] else {
|
||||
return
|
||||
}
|
||||
if statusIDs.contains(mainStatusID) {
|
||||
state = .notFound
|
||||
} else if case .displaying(_) = state {
|
||||
let mainStatus = mastodonController.persistentContainer.status(for: mainStatusID)!
|
||||
Task {
|
||||
await loadContext(for: mainStatus)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Loading
|
||||
|
||||
private func loadMainStatus() async {
|
||||
|
|
|
@ -101,6 +101,12 @@ class TrendingStatusesViewController: UIViewController {
|
|||
}
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handleStatusDeleted), name: .statusDeleted, object: nil)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
|
@ -137,6 +143,27 @@ class TrendingStatusesViewController: UIViewController {
|
|||
snapshot.appendItems(statuses.map { .status(id: $0.id, collapseState: .unknown, filterState: .unknown) })
|
||||
await dataSource.apply(snapshot)
|
||||
}
|
||||
|
||||
@objc private func handleStatusDeleted(_ notification: Foundation.Notification) {
|
||||
guard let userInfo = notification.userInfo,
|
||||
let accountID = mastodonController.accountInfo?.id,
|
||||
userInfo["accountID"] as? String == accountID,
|
||||
let statusIDs = userInfo["statusIDs"] as? [String] else {
|
||||
return
|
||||
}
|
||||
var snapshot = self.dataSource.snapshot()
|
||||
let toDelete = statusIDs
|
||||
.map { id in
|
||||
Item.status(id: id, collapseState: .unknown, filterState: .unknown)
|
||||
}
|
||||
.filter { item in
|
||||
snapshot.itemIdentifiers.contains(item)
|
||||
}
|
||||
if !toDelete.isEmpty {
|
||||
snapshot.deleteItems(toDelete)
|
||||
self.dataSource.apply(snapshot, animatingDifferences: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension TrendingStatusesViewController {
|
||||
|
|
|
@ -58,6 +58,31 @@ class NotificationsTableViewController: DiffableTimelineLikeTableViewController<
|
|||
|
||||
tableView.cellLayoutMarginsFollowReadableWidth = true
|
||||
tableView.allowsFocus = true
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handleStatusDeleted), name: .statusDeleted, object: nil)
|
||||
}
|
||||
|
||||
@objc private func handleStatusDeleted(_ notification: Foundation.Notification) {
|
||||
guard let userInfo = notification.userInfo,
|
||||
let accountID = mastodonController.accountInfo?.id,
|
||||
userInfo["accountID"] as? String == accountID,
|
||||
let statusIDs = userInfo["statusIDs"] as? [String] else {
|
||||
return
|
||||
}
|
||||
var snapshot = self.dataSource.snapshot()
|
||||
// this is not efficient, since the number of notifications is almost certainly greater than the number of deleted statuses
|
||||
// but we can't just check if the status is in the data source, since we don't have the corresponding notification/group
|
||||
let toDelete = snapshot.itemIdentifiers
|
||||
.filter { item in
|
||||
guard case .notificationGroup(let group) = item else {
|
||||
return false
|
||||
}
|
||||
return group.kind == .mention && statusIDs.contains(group.notifications.first!.status!.id)
|
||||
}
|
||||
if !toDelete.isEmpty {
|
||||
snapshot.deleteItems(toDelete)
|
||||
self.dataSource.apply(snapshot, animatingDifferences: true)
|
||||
}
|
||||
}
|
||||
|
||||
private func request(range: RequestRange) -> Request<[Pachyderm.Notification]> {
|
||||
|
|
|
@ -143,6 +143,8 @@ class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionVie
|
|||
filterer.filtersChanged = { [unowned self] actionsChanged in
|
||||
self.reapplyFilters(actionsChanged: actionsChanged)
|
||||
}
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handleStatusDeleted), name: .statusDeleted, object: nil)
|
||||
}
|
||||
|
||||
private func createDataSource() -> UICollectionViewDiffableDataSource<Section, Item> {
|
||||
|
@ -344,6 +346,31 @@ class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionVie
|
|||
}
|
||||
}
|
||||
|
||||
@objc private func handleStatusDeleted(_ notification: Foundation.Notification) {
|
||||
guard let userInfo = notification.userInfo,
|
||||
let accountID = mastodonController.accountInfo?.id,
|
||||
userInfo["accountID"] as? String == accountID,
|
||||
let statusIDs = userInfo["statusIDs"] as? [String] else {
|
||||
return
|
||||
}
|
||||
var snapshot = self.dataSource.snapshot()
|
||||
let toDelete = statusIDs
|
||||
.flatMap { id in
|
||||
// need to delete from both pinned and non-pinned sections
|
||||
[
|
||||
Item.status(id: id, collapseState: .unknown, filterState: .unknown, pinned: false),
|
||||
Item.status(id: id, collapseState: .unknown, filterState: .unknown, pinned: true),
|
||||
]
|
||||
}
|
||||
.filter { item in
|
||||
snapshot.itemIdentifiers.contains(item)
|
||||
}
|
||||
if !toDelete.isEmpty {
|
||||
snapshot.deleteItems(toDelete)
|
||||
self.dataSource.apply(snapshot, animatingDifferences: true)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ProfileStatusesViewController {
|
||||
|
@ -376,6 +403,7 @@ extension ProfileStatusesViewController {
|
|||
typealias TimelineItem = String
|
||||
|
||||
case header(String)
|
||||
// the status item must contain the pinned state, since a status can appear in both the pinned and regular sections simultaneously
|
||||
case status(id: String, collapseState: CollapseState, filterState: FilterState, pinned: Bool)
|
||||
case loadingIndicator
|
||||
case confirmLoadMore
|
||||
|
|
|
@ -121,6 +121,8 @@ class SearchResultsViewController: EnhancedTableViewController {
|
|||
.sink(receiveValue: performSearch(query:))
|
||||
|
||||
userActivity = UserActivityManager.searchActivity()
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handleStatusDeleted), name: .statusDeleted, object: nil)
|
||||
}
|
||||
|
||||
override func targetViewController(forAction action: Selector, sender: Any?) -> UIViewController? {
|
||||
|
@ -207,6 +209,28 @@ class SearchResultsViewController: EnhancedTableViewController {
|
|||
errorLabel.text = error.localizedDescription
|
||||
}
|
||||
|
||||
@objc private func handleStatusDeleted(_ notification: Foundation.Notification) {
|
||||
guard let userInfo = notification.userInfo,
|
||||
let accountID = mastodonController.accountInfo?.id,
|
||||
userInfo["accountID"] as? String == accountID,
|
||||
let statusIDs = userInfo["statusIDs"] as? [String] else {
|
||||
return
|
||||
}
|
||||
var snapshot = self.dataSource.snapshot()
|
||||
let toDelete = statusIDs
|
||||
.map { id in
|
||||
Item.status(id, .unknown)
|
||||
}
|
||||
.filter { item in
|
||||
snapshot.itemIdentifiers.contains(item)
|
||||
}
|
||||
if !toDelete.isEmpty {
|
||||
snapshot.deleteItems(toDelete)
|
||||
self.dataSource.apply(snapshot, animatingDifferences: true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Table view delegate
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
|
|
|
@ -146,6 +146,7 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
|||
_ = syncPositionIfNecessary(alwaysPrompt: true)
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handleStatusDeleted), name: .statusDeleted, object: nil)
|
||||
}
|
||||
|
||||
// separate method because InstanceTimelineViewController needs to be able to customize it
|
||||
|
@ -830,6 +831,26 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
|||
}
|
||||
}
|
||||
|
||||
@objc private func handleStatusDeleted(_ notification: Foundation.Notification) {
|
||||
guard let userInfo = notification.userInfo,
|
||||
let accountID = mastodonController.accountInfo?.id,
|
||||
userInfo["accountID"] as? String == accountID,
|
||||
let statusIDs = userInfo["statusIDs"] as? [String] else {
|
||||
return
|
||||
}
|
||||
var snapshot = self.dataSource.snapshot()
|
||||
let toDelete = statusIDs
|
||||
.map { id in
|
||||
Item.status(id: id, collapseState: .unknown, filterState: .unknown)
|
||||
}
|
||||
.filter { item in
|
||||
snapshot.itemIdentifiers.contains(item)
|
||||
}
|
||||
if !toDelete.isEmpty {
|
||||
snapshot.deleteItems(toDelete)
|
||||
self.dataSource.apply(snapshot, animatingDifferences: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension TimelineViewController {
|
||||
|
|
|
@ -231,7 +231,7 @@ extension MenuActionProvider {
|
|||
}), at: 1)
|
||||
}
|
||||
|
||||
var actionsSection: [UIAction] = []
|
||||
var actionsSection: [UIMenuElement] = []
|
||||
|
||||
if includeStatusButtonActions {
|
||||
actionsSection.insert(createAction(identifier: "reply", title: "Reply", systemImageName: "arrowshape.turn.up.left", handler: { [weak self] (_) in
|
||||
|
@ -257,9 +257,27 @@ extension MenuActionProvider {
|
|||
}))
|
||||
}
|
||||
|
||||
// only allowing pinning user's own statuses
|
||||
if account.id == status.account.id,
|
||||
mastodonController.instanceFeatures.profilePinnedStatuses {
|
||||
if status.poll != nil {
|
||||
actionsSection.append(createAction(identifier: "refresh", title: "Refresh Poll", systemImageName: "arrow.clockwise", handler: { [weak self] (_) in
|
||||
guard let mastodonController = self?.mastodonController else { return }
|
||||
let request = Client.getStatus(id: status.id)
|
||||
mastodonController.run(request, completion: { (response) in
|
||||
switch response {
|
||||
case .success(let status, _):
|
||||
// todo: this shouldn't really use the viewContext, but for some reason saving the
|
||||
// backgroundContext with the new version of the status isn't updating the viewContext
|
||||
DispatchQueue.main.async {
|
||||
mastodonController.persistentContainer.addOrUpdate(status: status, context: mastodonController.persistentContainer.viewContext)
|
||||
}
|
||||
case .failure(let error):
|
||||
self?.handleError(error, title: "Error Refreshing Poll")
|
||||
}
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
if account.id == status.account.id {
|
||||
if mastodonController.instanceFeatures.profilePinnedStatuses {
|
||||
let pinned = status.pinned ?? false
|
||||
toggleableSection.append(createAction(identifier: "pin", title: pinned ? "Unpin from Profile" : "Pin to Profile", systemImageName: pinned ? "pin.slash" : "pin", handler: { [weak self] (_) in
|
||||
guard let self = self else { return }
|
||||
|
@ -276,27 +294,20 @@ extension MenuActionProvider {
|
|||
}))
|
||||
}
|
||||
|
||||
if status.poll != nil {
|
||||
actionsSection.insert(createAction(identifier: "refresh", title: "Refresh Poll", systemImageName: "arrow.clockwise", handler: { [weak self] (_) in
|
||||
guard let mastodonController = self?.mastodonController else { return }
|
||||
let request = Client.getStatus(id: status.id)
|
||||
mastodonController.run(request, completion: { (response) in
|
||||
switch response {
|
||||
case .success(let status, _):
|
||||
// todo: this shouldn't really use the viewContext, but for some reason saving the
|
||||
// backgroundContext with the new version of the status isn't updating the viewContext
|
||||
DispatchQueue.main.async {
|
||||
mastodonController.persistentContainer.addOrUpdate(status: status, context: mastodonController.persistentContainer.viewContext)
|
||||
actionsSection.append(UIMenu(title: "Delete Status", image: UIImage(systemName: "trash"), children: [
|
||||
UIAction(title: "Cancel", handler: { _ in }),
|
||||
UIAction(title: "Delete Status", image: UIImage(systemName: "trash"), attributes: .destructive, handler: { [weak self] _ in
|
||||
guard let self,
|
||||
let navigationDelegate = self.navigationDelegate else {
|
||||
return
|
||||
}
|
||||
case .failure(let error):
|
||||
self?.handleError(error, title: "Error Refreshing Poll")
|
||||
Task { @MainActor in
|
||||
let service = DeleteStatusService(status: status, mastodonController: mastodonController, presenter: navigationDelegate)
|
||||
await service.run()
|
||||
}
|
||||
})
|
||||
}), at: 0)
|
||||
}
|
||||
|
||||
// can only report other people's posts
|
||||
if account.id != status.account.id {
|
||||
]))
|
||||
} else {
|
||||
actionsSection.append(createAction(identifier: "report", title: "Report", systemImageName: "flag", handler: { [weak self] _ in
|
||||
let report = EditedReport(accountID: status.account.id)
|
||||
report.statusIDs = [status.id]
|
||||
|
|
Loading…
Reference in New Issue