mirror of
https://github.com/kean/Pulse.git
synced 2026-05-30 21:07:33 +00:00
183 lines
5.1 KiB
Swift
183 lines
5.1 KiB
Swift
// The MIT License (MIT)
|
||
//
|
||
// Copyright (c) 2020-2026 Alexander Grebenyuk (github.com/kean).
|
||
|
||
import SwiftUI
|
||
|
||
#if os(iOS) || os(visionOS)
|
||
import UIKit
|
||
|
||
package struct ShareView: UIViewControllerRepresentable {
|
||
var activityItems: [Any]
|
||
var applicationActivities: [UIActivity]?
|
||
private let cleanup: () -> Void
|
||
private var completion: (() -> Void)?
|
||
|
||
package init(activityItems: [Any]) {
|
||
self.activityItems = activityItems
|
||
self.cleanup = {}
|
||
}
|
||
|
||
package init(_ items: ShareItems) {
|
||
self.activityItems = items.items
|
||
self.cleanup = items.cleanup
|
||
}
|
||
|
||
package func onCompletion(_ completion: @escaping () -> Void) -> Self {
|
||
var copy = self
|
||
copy.completion = completion
|
||
return copy
|
||
}
|
||
|
||
package func makeUIViewController(context: UIViewControllerRepresentableContext<ShareView>) -> UIActivityViewController {
|
||
let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities)
|
||
controller.completionWithItemsHandler = { _, _, _, _ in
|
||
cleanup()
|
||
completion?()
|
||
}
|
||
return controller
|
||
}
|
||
|
||
package func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext<ShareView>) {
|
||
}
|
||
}
|
||
#endif
|
||
|
||
#if os(macOS)
|
||
import AppKit
|
||
import Pulse
|
||
|
||
package struct ShareView: View {
|
||
package let items: ShareItems
|
||
|
||
private var cleanup: (() -> Void)?
|
||
private var completion: (() -> Void)?
|
||
|
||
package init(_ items: ShareItems) {
|
||
self.items = items
|
||
self.cleanup = items.cleanup
|
||
}
|
||
|
||
package func onCompletion(_ completion: @escaping () -> Void) -> Self {
|
||
var copy = self
|
||
copy.completion = completion
|
||
return copy
|
||
}
|
||
|
||
package var body: some View {
|
||
VStack(alignment: .leading, spacing: 0) {
|
||
let services = NSSharingService.sharingServices(forItems: items.items)
|
||
ForEach(services, id: \.title) { service in
|
||
Item(item: service) {
|
||
service.perform(withItems: items.items)
|
||
}
|
||
}
|
||
}.padding(4)
|
||
}
|
||
|
||
private struct Item: View {
|
||
let item: NSSharingService
|
||
let action: () -> Void
|
||
@State private var isHighlighted = false
|
||
|
||
var body: some View {
|
||
Button(action: action) {
|
||
HStack {
|
||
Image(nsImage: item.image)
|
||
Text(item.title)
|
||
Spacer()
|
||
}.contentShape(Rectangle())
|
||
}
|
||
.buttonStyle(.plain)
|
||
.padding(4)
|
||
.onHover { isHighlighted = $0 }
|
||
.background {
|
||
if isHighlighted {
|
||
Color.separator.cornerRadius(4)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
#endif
|
||
|
||
#if os(macOS)
|
||
@available(iOS 18, tvOS 18, macOS 15, watchOS 11, visionOS 1, *)
|
||
package struct ShareNetworkTaskView: View {
|
||
@ObservedObject var task: NetworkTaskEntity
|
||
|
||
@AppStorage("com-github-kean-selected-task-sharing-option") private var output: Output = .plainText
|
||
|
||
@State private var items: ShareItems?
|
||
@Environment(\.store) private var store
|
||
|
||
package init(task: NetworkTaskEntity) {
|
||
self.task = task
|
||
}
|
||
|
||
package var body: some View {
|
||
VStack(spacing: 0) {
|
||
VStack(spacing: 8) {
|
||
NetworkRequestStatusCell(viewModel: .init(task: task, store: store))
|
||
HStack {
|
||
VStack(alignment: .leading) {
|
||
Text(task.httpMethod ?? "GET").fontWeight(.semibold)
|
||
Text(task.url ?? "–")
|
||
.lineLimit(3)
|
||
.fixedSize(horizontal: false, vertical: true)
|
||
}
|
||
Spacer()
|
||
}
|
||
}
|
||
.padding(8)
|
||
Picker("", selection: $output) {
|
||
ForEach(Output.allCases, id: \.self) {
|
||
Text($0.rawValue).tag($0.rawValue)
|
||
}
|
||
}
|
||
.labelsHidden()
|
||
.padding(8)
|
||
Divider()
|
||
if let items = items {
|
||
ShareView(items)
|
||
}
|
||
}
|
||
.onChange(of: output, perform: render)
|
||
.onAppear { render(with: output) }
|
||
.frame(width: 240)
|
||
}
|
||
|
||
private func render(with output: Output) {
|
||
var asString: NSAttributedString {
|
||
TextRenderer(options: .sharing).make {
|
||
$0.render(task, content: .sharing, store: store)
|
||
}
|
||
}
|
||
switch output {
|
||
case .plainText:
|
||
items = ShareService.share(asString, as: .plainText)
|
||
case .html:
|
||
items = ShareService.share(asString, as: .html)
|
||
case .curl:
|
||
items = ShareItems([task.cURLDescription()])
|
||
}
|
||
}
|
||
|
||
enum Output: String, CaseIterable {
|
||
case plainText = "Plain Text"
|
||
case html = "HTML"
|
||
case curl = "cURL"
|
||
}
|
||
}
|
||
|
||
#if DEBUG
|
||
@available(iOS 18, tvOS 18, macOS 15, watchOS 11, visionOS 1, *)
|
||
#Preview {
|
||
ShareNetworkTaskView(task: LoggerStore.demo.entity(for: .login))
|
||
.frame(height: 400)
|
||
}
|
||
#endif
|
||
|
||
#endif
|