Files
omnivore/apple/OmnivoreKit/Sources/App/AppExtensions/Share/ShareExtensionScene.swift
2022-02-24 15:07:32 -08:00

103 lines
3.8 KiB
Swift

import Combine
import Foundation
import Models
import Services
import SwiftUI
import Utils
import Views
public extension PlatformViewController {
static func makeShareExtensionController(extensionContext: NSExtensionContext?) -> PlatformViewController {
let viewModel = ShareExtensionViewModel.make(extensionContext: extensionContext)
let rootView = ShareExtensionView(viewModel: viewModel)
let hostingController = PlatformHostingController(rootView: rootView)
#if os(iOS)
hostingController.view.layer.cornerRadius = 12
hostingController.view.layer.masksToBounds = true
hostingController.view.layer.isOpaque = false
#endif
return hostingController
}
}
extension ShareExtensionViewModel {
static func make(extensionContext: NSExtensionContext?) -> ShareExtensionViewModel {
let viewModel = ShareExtensionViewModel()
viewModel.bind(extensionContext: extensionContext)
return viewModel
}
func bind(extensionContext: NSExtensionContext?) {
performActionSubject.sink { [weak self] action in
switch action {
case let .savePage(requestID):
self?.savePage(extensionContext: extensionContext, requestId: requestID)
case .dismissButtonTapped:
extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
case .copyLinkButtonTapped:
print("copy link button tapped")
case .readNowButtonTapped:
#if os(iOS)
if let application = UIApplication.value(forKeyPath: #keyPath(UIApplication.shared)) as? UIApplication {
let deepLinkUrl = NSURL(string: "omnivore://shareExtensionRequestID/\(self?.requestID ?? "")")
application.perform(NSSelectorFromString("openURL:"), with: deepLinkUrl)
}
#endif
extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
case .archiveButtonTapped:
print("archive button tapped")
}
}
.store(in: &subscriptions)
}
private func savePage(extensionContext: NSExtensionContext?, requestId: String) {
PageScraper.scrape(extensionContext: extensionContext) { [weak self] result in
switch result {
case let .success(payload):
self?.persist(pageScrapePayload: payload, requestId: requestId)
case let .failure(error):
self?.debugText = error.message
}
}
}
private func persist(pageScrapePayload: PageScrapePayload, requestId: String) {
let services = Services()
guard services.authenticator.hasValidAuthToken else {
status = .failed(error: .unauthorized)
return
}
let saveLinkPublisher: AnyPublisher<Void, SaveArticleError> = {
if pageScrapePayload.contentType == .pdf {
return services.dataService.uploadPDFPublisher(pageScrapePayload: pageScrapePayload, requestId: requestId)
} else if pageScrapePayload.html != nil {
return services.dataService.savePagePublisher(pageScrapePayload: pageScrapePayload, requestId: requestId)
} else {
return services.dataService.saveUrlPublisher(pageScrapePayload: pageScrapePayload, requestId: requestId)
}
}()
saveLinkPublisher
.sink { [weak self] completion in
guard case let .failure(error) = completion else { return }
self?.debugText = "saveArticleError: \(error)"
self?.status = .failed(error: error)
} receiveValue: { [weak self] _ in
self?.status = .successfullySaved
}
.store(in: &subscriptions)
// Using viewerPublisher to get fast feedback for auth/network errors
services.dataService.viewerPublisher()
.sink { [weak self] completion in
guard case let .failure(error) = completion else { return }
self?.debugText = "saveArticleError: \(error)"
self?.status = .failed(error: .unknown(description: ""))
} receiveValue: { _ in }
.store(in: &subscriptions)
}
}