IceCubesApp/Packages/StatusKit/Sources/StatusKit/Editor/ToolbarItems.swift
2024-01-09 16:17:34 +01:00

175 lines
5.7 KiB
Swift

import Env
import Models
import StoreKit
import SwiftUI
import DesignSystem
extension StatusEditor {
@MainActor
struct ToolbarItems: ToolbarContent {
@State private var isLanguageConfirmPresented = false
@State private var isDismissAlertPresented: Bool = false
@State private var isDraftsSheetDisplayed: Bool = false
let mainSEVM: ViewModel
let focusedSEVM: ViewModel
let followUpSEVMs: [ViewModel]
@Environment(\.modelContext) private var context
@Environment(UserPreferences.self) private var preferences
@Environment(Theme.self) private var theme
#if targetEnvironment(macCatalyst)
@Environment(\.dismissWindow) private var dismissWindow
#else
@Environment(\.dismiss) private var dismiss
#endif
var body: some ToolbarContent {
if !mainSEVM.mode.isInShareExtension {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
isDraftsSheetDisplayed = true
} label: {
Image(systemName: "pencil.and.list.clipboard")
}
.accessibilityLabel("accessibility.editor.button.drafts")
.popover(isPresented: $isDraftsSheetDisplayed) {
if UIDevice.current.userInterfaceIdiom == .phone {
draftsListView
.presentationDetents([.medium])
} else {
draftsListView
.frame(width: 400, height: 500)
}
}
}
}
ToolbarItem(placement: .navigationBarTrailing) {
Button {
Task {
mainSEVM.evaluateLanguages()
if preferences.autoDetectPostLanguage, let _ = mainSEVM.languageConfirmationDialogLanguages {
isLanguageConfirmPresented = true
} else {
await postAllStatus()
}
}
} label: {
Image(systemName: "paperplane.fill")
.bold()
}
.buttonStyle(.borderedProminent)
.disabled(!mainSEVM.canPost || mainSEVM.isPosting)
.keyboardShortcut(.return, modifiers: .command)
.confirmationDialog("", isPresented: $isLanguageConfirmPresented, actions: {
languageConfirmationDialog
})
}
ToolbarItem(placement: .navigationBarLeading) {
Button {
if mainSEVM.shouldDisplayDismissWarning {
isDismissAlertPresented = true
} else {
close()
NotificationCenter.default.post(name: .shareSheetClose,
object: nil)
}
} label: {
Image(systemName: "xmark")
}
.keyboardShortcut(.cancelAction)
.confirmationDialog(
"",
isPresented: $isDismissAlertPresented,
actions: {
Button("status.draft.delete", role: .destructive) {
close()
NotificationCenter.default.post(name: .shareSheetClose,
object: nil)
}
Button("status.draft.save") {
context.insert(Draft(content: mainSEVM.statusText.string))
close()
NotificationCenter.default.post(name: .shareSheetClose,
object: nil)
}
Button("action.cancel", role: .cancel) {}
}
)
}
}
@discardableResult
private func postStatus(with model: ViewModel, isMainPost: Bool) async -> Status? {
let status = await model.postStatus()
if status != nil, isMainPost {
close()
SoundEffectManager.shared.playSound(.tootSent)
NotificationCenter.default.post(name: .shareSheetClose, object: nil)
#if !targetEnvironment(macCatalyst)
if !mainSEVM.mode.isInShareExtension, !preferences.requestedReview {
if let scene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene {
SKStoreReviewController.requestReview(in: scene)
}
preferences.requestedReview = true
}
#endif
}
return status
}
private func postAllStatus() async {
guard var latestPost = await postStatus(with: mainSEVM, isMainPost: true) else { return }
for p in followUpSEVMs {
p.mode = .replyTo(status: latestPost)
guard let post = await postStatus(with: p, isMainPost: false) else {
break
}
latestPost = post
}
}
#if targetEnvironment(macCatalyst)
private func close() { dismissWindow() }
#else
private func close() { dismiss() }
#endif
@ViewBuilder
private var languageConfirmationDialog: some View {
if let (detected: detected, selected: selected) = mainSEVM.languageConfirmationDialogLanguages,
let detectedLong = Locale.current.localizedString(forLanguageCode: detected),
let selectedLong = Locale.current.localizedString(forLanguageCode: selected)
{
Button("status.editor.language-select.confirmation.detected-\(detectedLong)") {
mainSEVM.selectedLanguage = detected
Task { await postAllStatus() }
}
Button("status.editor.language-select.confirmation.selected-\(selectedLong)") {
mainSEVM.selectedLanguage = selected
Task { await postAllStatus() }
}
Button("action.cancel", role: .cancel) {
mainSEVM.languageConfirmationDialogLanguages = nil
}
} else {
EmptyView()
}
}
private var draftsListView: some View {
DraftsListView(selectedDraft: .init(get: {
nil
}, set: { draft in
if let draft {
focusedSEVM.insertStatusText(text: draft.content)
}
}))
}
}
}