IceCubesApp/Packages/Status/Sources/Status/Row/Subviews/StatusRowContextMenu.swift

269 lines
10 KiB
Swift
Raw Normal View History

2023-02-21 06:23:42 +00:00
import DesignSystem
2023-01-17 10:36:01 +00:00
import Env
2023-01-04 17:37:58 +00:00
import Foundation
2023-02-19 14:29:07 +00:00
import Network
2023-02-21 06:23:42 +00:00
import SwiftUI
2023-01-04 17:37:58 +00:00
struct StatusRowContextMenu: View {
2023-02-19 14:29:07 +00:00
@Environment(\.displayScale) var displayScale
2023-02-21 06:23:42 +00:00
@EnvironmentObject private var client: Client
2023-02-19 14:29:07 +00:00
@EnvironmentObject private var sceneDelegate: SceneDelegate
@EnvironmentObject private var preferences: UserPreferences
2023-01-04 17:37:58 +00:00
@EnvironmentObject private var account: CurrentAccount
@EnvironmentObject private var currentInstance: CurrentInstance
@EnvironmentObject private var statusDataController: StatusDataController
2023-01-17 10:36:01 +00:00
2023-01-04 17:37:58 +00:00
@ObservedObject var viewModel: StatusRowViewModel
2023-02-21 06:23:42 +00:00
var boostLabel: some View {
if self.viewModel.status.visibility == .priv && self.viewModel.status.account.id == self.account.account?.id {
if self.statusDataController.isReblogged {
return Label("status.action.unboost", systemImage: "lock.rotation")
}
return Label("status.action.boost-to-followers", systemImage: "lock.rotation")
}
2023-02-21 06:23:42 +00:00
if self.statusDataController.isReblogged {
return Label("status.action.unboost", image: "Rocket")
}
return Label("status.action.boost", image: "Rocket")
}
2023-02-21 06:23:42 +00:00
2023-01-04 17:37:58 +00:00
var body: some View {
if !viewModel.isRemote {
Button { Task {
await statusDataController.toggleFavorite(remoteStatus: nil)
} } label: {
Label(statusDataController.isFavorited ? "status.action.unfavorite" : "status.action.favorite", systemImage: "star")
2023-01-04 17:37:58 +00:00
}
Button { Task {
await statusDataController.toggleReblog(remoteStatus: nil)
} } label: {
boostLabel
2023-01-04 17:37:58 +00:00
}
.disabled(viewModel.status.visibility == .direct || viewModel.status.visibility == .priv && viewModel.status.account.id != account.account?.id)
2023-01-09 18:26:56 +00:00
Button { Task {
await statusDataController.toggleBookmark(remoteStatus: nil)
2023-01-09 18:26:56 +00:00
} } label: {
Label(statusDataController.isBookmarked ? "status.action.unbookmark" : "status.action.bookmark",
2023-01-09 18:26:56 +00:00
systemImage: "bookmark")
}
Button {
viewModel.routerPath.presentedSheet = .replyToStatusEditor(status: viewModel.status)
} label: {
Label("status.action.reply", systemImage: "arrowshape.turn.up.left")
}
2023-01-04 17:37:58 +00:00
Button {
viewModel.routerPath.presentedSheet = .quoteStatusEditor(status: viewModel.status)
2023-01-04 17:37:58 +00:00
} label: {
Label("status.action.quote", systemImage: "quote.bubble")
2023-01-04 17:37:58 +00:00
}
.disabled(viewModel.status.visibility == .direct || viewModel.status.visibility == .priv)
2023-01-04 17:37:58 +00:00
}
2023-01-17 10:36:01 +00:00
2023-01-07 17:01:06 +00:00
Divider()
2023-01-17 10:36:01 +00:00
2023-02-19 14:29:07 +00:00
Menu("status.action.share-title") {
if let urlString = viewModel.status.reblog?.url ?? viewModel.status.url,
let url = URL(string: urlString)
{
ShareLink(item: url,
subject: Text(viewModel.status.reblog?.account.safeDisplayName ?? viewModel.status.account.safeDisplayName),
2023-03-13 12:38:28 +00:00
message: Text(viewModel.status.reblog?.content.asRawText ?? viewModel.status.content.asRawText))
{
2023-02-19 14:29:07 +00:00
Label("status.action.share", systemImage: "square.and.arrow.up")
}
2023-02-21 06:23:42 +00:00
2023-02-19 14:29:07 +00:00
ShareLink(item: url) {
Label("status.action.share-link", systemImage: "link")
}
2023-02-21 06:23:42 +00:00
2023-02-19 14:29:07 +00:00
Button {
let view = HStack {
StatusRowView(viewModel: { viewModel })
2023-02-19 14:29:07 +00:00
.padding(16)
}
.environment(\.isInCaptureMode, true)
.environmentObject(Theme.shared)
.environmentObject(preferences)
.environmentObject(account)
.environmentObject(currentInstance)
.environmentObject(SceneDelegate())
.environmentObject(QuickLook())
.environmentObject(viewModel.client)
.preferredColorScheme(Theme.shared.selectedScheme == .dark ? .dark : .light)
2023-02-19 15:03:27 +00:00
.foregroundColor(Theme.shared.labelColor)
.frame(width: sceneDelegate.windowWidth - 12)
.tint(Theme.shared.tintColor)
2023-02-19 14:29:07 +00:00
let renderer = ImageRenderer(content: view)
renderer.scale = displayScale
2023-02-19 15:03:27 +00:00
renderer.isOpaque = false
2023-02-19 14:29:07 +00:00
if let image = renderer.uiImage {
viewModel.routerPath.presentedSheet = .shareImage(image: image, status: viewModel.status)
}
} label: {
Label("status.action.share-image", systemImage: "photo")
}
2023-01-17 10:36:01 +00:00
}
}
2023-01-17 10:36:01 +00:00
if let url = URL(string: viewModel.status.reblog?.url ?? viewModel.status.url ?? "") {
2023-02-01 06:09:41 +00:00
Button { UIApplication.shared.open(url) } label: {
Label("status.action.view-in-browser", systemImage: "safari")
2023-01-04 17:37:58 +00:00
}
}
2023-01-17 10:36:01 +00:00
Button {
2023-02-06 17:41:12 +00:00
UIPasteboard.general.string = viewModel.status.reblog?.content.asRawText ?? viewModel.status.content.asRawText
} label: {
Label("status.action.copy-text", systemImage: "doc.on.doc")
}
Button {
UIPasteboard.general.string = viewModel.status.reblog?.url ?? viewModel.status.url
} label: {
Label("status.action.copy-link", systemImage: "link")
}
if let lang = preferences.serverPreferences?.postLanguage ?? Locale.current.language.languageCode?.identifier
{
Button {
Task {
await viewModel.translate(userLang: lang)
}
} label: {
2023-02-22 18:09:39 +00:00
Label("status.action.translate", systemImage: "captions.bubble")
}
2023-03-19 15:28:06 +00:00
if !viewModel.alwaysTranslateWithDeepl {
2023-03-14 17:50:19 +00:00
Button {
Task {
await viewModel.translateWithDeepL(userLang: lang)
}
} label: {
Label("status.action.translate-with-deepl", systemImage: "captions.bubble")
}
}
}
2023-01-04 17:37:58 +00:00
if account.account?.id == viewModel.status.reblog?.account.id ?? viewModel.status.account.id {
Section("status.action.section.your-post") {
2023-01-04 17:37:58 +00:00
Button {
Task {
if viewModel.isPinned {
await viewModel.unPin()
} else {
await viewModel.pin()
}
}
} label: {
Label(viewModel.isPinned ? "status.action.unpin" : "status.action.pin", systemImage: viewModel.isPinned ? "pin.fill" : "pin")
2023-01-04 17:37:58 +00:00
}
if currentInstance.isEditSupported {
Button {
viewModel.routerPath.presentedSheet = .editStatusEditor(status: viewModel.status)
} label: {
Label("status.action.edit", systemImage: "pencil")
}
2023-01-04 17:37:58 +00:00
}
Button(role: .destructive,
action: { viewModel.showDeleteAlert = true },
2023-02-12 15:29:41 +00:00
label: { Label("status.action.delete", systemImage: "trash") })
2023-01-04 17:37:58 +00:00
}
} else {
if !viewModel.isRemote {
Section(viewModel.status.reblog?.account.acct ?? viewModel.status.account.acct) {
Button {
viewModel.routerPath.presentedSheet = .mentionStatusEditor(account: viewModel.status.reblog?.account ?? viewModel.status.account, visibility: .pub)
} label: {
Label("status.action.mention", systemImage: "at")
}
Button {
viewModel.routerPath.presentedSheet = .mentionStatusEditor(account: viewModel.status.reblog?.account ?? viewModel.status.account, visibility: .direct)
} label: {
Label("status.action.message", systemImage: "tray.full")
}
2023-07-19 05:46:25 +00:00
if viewModel.authorRelationship?.blocking == true {
Button {
Task {
do {
let operationAccount = viewModel.status.reblog?.account ?? viewModel.status.account
viewModel.authorRelationship = try await client.post(endpoint: Accounts.unblock(id: operationAccount.id))
} catch {
print("Error while unblocking: \(error.localizedDescription)")
}
}
} label: {
Label("account.action.unblock", systemImage: "person.crop.circle.badge.exclamationmark")
}
} else {
Button {
Task {
do {
let operationAccount = viewModel.status.reblog?.account ?? viewModel.status.account
viewModel.authorRelationship = try await client.post(endpoint: Accounts.block(id: operationAccount.id))
} catch {
print("Error while blocking: \(error.localizedDescription)")
}
}
} label: {
Label("account.action.block", systemImage: "person.crop.circle.badge.xmark")
}
}
2023-07-19 05:46:25 +00:00
if viewModel.authorRelationship?.muting == true {
Button {
Task {
do {
let operationAccount = viewModel.status.reblog?.account ?? viewModel.status.account
viewModel.authorRelationship = try await client.post(endpoint: Accounts.unmute(id: operationAccount.id))
} catch {
print("Error while unmuting: \(error.localizedDescription)")
}
}
} label: {
Label("account.action.unmute", systemImage: "speaker")
}
} else {
Menu {
ForEach(Duration.mutingDurations(), id: \.rawValue) { duration in
Button(duration.description) {
Task {
do {
let operationAccount = viewModel.status.reblog?.account ?? viewModel.status.account
viewModel.authorRelationship = try await client.post(endpoint: Accounts.mute(id: operationAccount.id, json: MuteData(duration: duration.rawValue)))
} catch {
print("Error while muting: \(error.localizedDescription)")
}
}
}
}
} label: {
Label("account.action.mute", systemImage: "speaker.slash")
}
}
2023-01-04 17:37:58 +00:00
}
}
2023-02-13 20:12:18 +00:00
Section {
Button(role: .destructive) {
viewModel.routerPath.presentedSheet = .report(status: viewModel.status.reblogAsAsStatus ?? viewModel.status)
2023-02-13 20:12:18 +00:00
} label: {
Label("status.action.report", systemImage: "exclamationmark.bubble")
}
}
2023-01-04 17:37:58 +00:00
}
}
}
2023-02-19 14:29:07 +00:00
struct ActivityView: UIViewControllerRepresentable {
let image: Image
2023-02-21 06:23:42 +00:00
func makeUIViewController(context _: UIViewControllerRepresentableContext<ActivityView>) -> UIActivityViewController {
2023-02-19 14:29:07 +00:00
return UIActivityViewController(activityItems: [image], applicationActivities: nil)
}
2023-02-21 06:23:42 +00:00
func updateUIViewController(_: UIActivityViewController, context _: UIViewControllerRepresentableContext<ActivityView>) {}
2023-02-19 14:29:07 +00:00
}