Files
omnivore/apple/OmnivoreKit/Sources/App/Views/Profile/NewsletterEmailsView.swift
2023-12-20 14:35:59 +08:00

186 lines
4.9 KiB
Swift

import Models
import PopupView
import Services
import SwiftUI
import Transmission
import Views
@MainActor final class NewsletterEmailsViewModel: ObservableObject {
@Published var isLoading = false
@Published var showAddressCopied = false
@Published var emails = [NewsletterEmail]()
func loadEmails(dataService: DataService) async {
isLoading = true
do {
let objectIDs = try await dataService.newsletterEmails()
await dataService.viewContext.perform { [weak self] in
self?.emails = objectIDs.compactMap { dataService.viewContext.object(with: $0) as? NewsletterEmail }
}
} catch {
print("ERROR LOADING EMAILS: ", error)
}
isLoading = false
}
func createEmail(dataService: DataService) async {
isLoading = true
if let objectID = try? await dataService.createNewsletter() {
await dataService.viewContext.perform { [weak self] in
if let item = dataService.viewContext.object(with: objectID) as? NewsletterEmail {
self?.emails.insert(item, at: 0)
}
}
}
isLoading = false
}
//
// func updateEmail(dataService: DataService, subscription: Subscription, folder: String? = nil, fetchContent: Bool? = nil) async {
// operationMessage = "Updating subscription..."
// operationStatus = .isPerforming
// do {
// try await dataService.updateSubscription(subscription.subscriptionID, folder: folder, fetchContent: fetchContent)
// operationMessage = "Subscription updated"
// operationStatus = .success
// } catch {
// operationMessage = "Failed to update subscription"
// operationStatus = .failure
// }
// }
}
struct NewsletterEmailsView: View {
@EnvironmentObject var dataService: DataService
@StateObject var viewModel = NewsletterEmailsViewModel()
@State var snackbarOperation: SnackbarOperation?
var body: some View {
Group {
WindowLink(level: .alert, transition: .move(edge: .bottom), isPresented: $viewModel.showAddressCopied) {
MessageToast()
} label: {
EmptyView()
}
#if os(iOS)
Form {
innerBody
}
#elseif os(macOS)
List {
innerBody
}
.listStyle(InsetListStyle())
#endif
}
.task { await viewModel.loadEmails(dataService: dataService) }
}
private var innerBody: some View {
Group {
if !viewModel.emails.isEmpty {
ForEach(viewModel.emails) { email in
Section {
NewsletterEmailRow(viewModel: viewModel, email: email, folderSelection: email.folder)
}
}
}
Section {
Text(LocalText.newslettersDescription)
Button(
action: {
Task { await viewModel.createEmail(dataService: dataService) }
},
label: {
Label(title: {
Text(LocalText.createNewEmailMessage)
}, icon: {
Image.addLink
})
}
)
.disabled(viewModel.isLoading)
}
}
.navigationTitle(LocalText.emailsGeneric)
}
}
struct NewsletterEmailRow: View {
@StateObject var viewModel: NewsletterEmailsViewModel
@State var email: NewsletterEmail
@State var folderSelection: String?
var body: some View {
VStack {
HStack {
Text(email.unwrappedEmail)
Spacer()
Button(
action: {
#if os(iOS)
UIPasteboard.general.string = email.email
#endif
#if os(macOS)
let pasteBoard = NSPasteboard.general
pasteBoard.clearContents()
pasteBoard.writeObjects([newsletterEmail.unwrappedEmail as NSString])
#endif
viewModel.showAddressCopied = true
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(2000)) {
viewModel.showAddressCopied = false
}
},
label: {
Text("Copy")
}
)
}
// Divider()
// Picker("Destination Folder", selection: $folderSelection) {
// Text("Inbox").tag("inbox")
// Text("Following").tag("following")
// }
// .pickerStyle(MenuPickerStyle())
// .onChange(of: folderSelection) { newValue in
// Task {
// viewModel.showOperationToast = true
// await viewModel.updateEmail(dataService: dataService, email: email, folder: newValue)
// DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1500)) {
// viewModel.showOperationToast = false
// }
// }
// }
}
}
}
struct MessageToast: View {
var body: some View {
VStack {
HStack {
Text("Address copied")
Spacer()
}
.padding(10)
.frame(minHeight: 50)
.frame(maxWidth: .infinity)
.background(Color(hex: "2A2A2A"))
.cornerRadius(4.0)
.tint(Color.green)
}
.padding(.bottom, 70)
.padding(.horizontal, 10)
.ignoresSafeArea(.all, edges: .bottom)
}
}