mirror of
https://github.com/kean/Pulse.git
synced 2026-05-30 21:07:33 +00:00
Remove ShareEntitiesView
This commit is contained in:
@@ -78,7 +78,6 @@
|
||||
0C9F05002884F34A0035239F /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0C9F04FF2884F34A0035239F /* Preview Assets.xcassets */; };
|
||||
0C9F050C2884FA7D0035239F /* repos.json in Resources */ = {isa = PBXBuildFile; fileRef = 0CFF9BD825D6199A0069DB6A /* repos.json */; };
|
||||
0CCBDDC02610BDBC00DCB60C /* repos.json in Resources */ = {isa = PBXBuildFile; fileRef = 0CFF9BD825D6199A0069DB6A /* repos.json */; };
|
||||
0CD7E0BB297326EC00A255B7 /* ShareEntitiesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CD7E0BA297326EC00A255B7 /* ShareEntitiesView.swift */; };
|
||||
0CD7E0BD29732C8E00A255B7 /* ShareStoreTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CD7E0BC29732C8E00A255B7 /* ShareStoreTask.swift */; };
|
||||
0CDC3BEA2970FA47003BD1FF /* ConsoleSearchListSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CDC3BE92970FA47003BD1FF /* ConsoleSearchListSelectionView.swift */; };
|
||||
0CDC3BED2971B936003BD1FF /* ConsoleSearchLogLevelsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CDC3BEC2971B936003BD1FF /* ConsoleSearchLogLevelsCell.swift */; };
|
||||
@@ -528,7 +527,6 @@
|
||||
0C9F04FC2884F34A0035239F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
0C9F04FF2884F34A0035239F /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||
0C9F05012884F34A0035239F /* Pulse_Demo_macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Pulse_Demo_macOS.entitlements; sourceTree = "<group>"; };
|
||||
0CD7E0BA297326EC00A255B7 /* ShareEntitiesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareEntitiesView.swift; sourceTree = "<group>"; };
|
||||
0CD7E0BC29732C8E00A255B7 /* ShareStoreTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareStoreTask.swift; sourceTree = "<group>"; };
|
||||
0CDC3BE92970FA47003BD1FF /* ConsoleSearchListSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsoleSearchListSelectionView.swift; sourceTree = "<group>"; };
|
||||
0CDC3BEC2971B936003BD1FF /* ConsoleSearchLogLevelsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsoleSearchLogLevelsCell.swift; sourceTree = "<group>"; };
|
||||
@@ -1180,7 +1178,6 @@
|
||||
0CF0D59C296F189500EED9D4 /* KeyValueSectionViewModel.swift */,
|
||||
0CF0D59E296F189500EED9D4 /* WebView.swift */,
|
||||
0CF0D5A5296F189500EED9D4 /* StoreShareView.swift */,
|
||||
0CD7E0BA297326EC00A255B7 /* ShareEntitiesView.swift */,
|
||||
0CF0D5A6296F189500EED9D4 /* SearchBar-ios.swift */,
|
||||
0CF0D5A7296F189500EED9D4 /* TimingView.swift */,
|
||||
0CF0D5A8296F189500EED9D4 /* InfoRow.swift */,
|
||||
@@ -2050,7 +2047,6 @@
|
||||
0CF0D659296F189600EED9D4 /* ConsoleSettings.swift in Sources */,
|
||||
0CF0D61B296F189600EED9D4 /* ShareItems.swift in Sources */,
|
||||
0CF0D683296F189600EED9D4 /* ConsoleMessageTableCell.swift in Sources */,
|
||||
0CD7E0BB297326EC00A255B7 /* ShareEntitiesView.swift in Sources */,
|
||||
0CF0D623296F189600EED9D4 /* SearchBar-macos.swift in Sources */,
|
||||
0CE364F72971D1EA0063DFED /* ConsoleSearchCustomFiltersSection.swift in Sources */,
|
||||
0C40C0A8296F9CBA009ECF16 /* ConsoleSearchPinsCell.swift in Sources */,
|
||||
|
||||
@@ -34,13 +34,18 @@ public struct ConsoleView: View {
|
||||
Button(action: $0) { Text("Close") }
|
||||
},
|
||||
trailing: HStack {
|
||||
Menu(content: { shareMenu }) {
|
||||
Image(systemName: "square.and.arrow.up")
|
||||
if let _ = selectedShareOutput {
|
||||
ProgressView()
|
||||
.frame(width: 27, height: 27)
|
||||
} else {
|
||||
Menu(content: { shareMenu }) {
|
||||
Image(systemName: "square.and.arrow.up")
|
||||
}
|
||||
.disabled(selectedShareOutput != nil)
|
||||
}
|
||||
ConsoleContextMenu(store: viewModel.store, insights: viewModel.insightsViewModel, isShowingAsText: $isShowingAsText)
|
||||
}
|
||||
)
|
||||
.overlay(sharingOverlay) // TODO: use safeAreaInset instead on iOS 15
|
||||
.sheet(item: $shareItems, content: ShareView.init)
|
||||
.sheet(isPresented: $isShowingAsText) {
|
||||
NavigationView {
|
||||
@@ -53,37 +58,24 @@ public struct ConsoleView: View {
|
||||
|
||||
@ViewBuilder
|
||||
private var shareMenu: some View {
|
||||
Button(action: { withAnimation { selectedShareOutput = .plainText } }) {
|
||||
Button(action: { share(as: .plainText) }) {
|
||||
Label("Share as Text", systemImage: "square.and.arrow.up")
|
||||
}
|
||||
Button(action: { withAnimation { selectedShareOutput = .html } }) {
|
||||
Button(action: { share(as: .html) }) {
|
||||
Label("Share as HTML", systemImage: "square.and.arrow.up")
|
||||
}
|
||||
#if os(iOS)
|
||||
Button(action: { withAnimation { selectedShareOutput = .pdf} }) {
|
||||
Button(action: { share(as: .pdf) }) {
|
||||
Label("Share as PDF", systemImage: "square.and.arrow.up")
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ViewBuilder var sharingOverlay: some View {
|
||||
if let output = selectedShareOutput {
|
||||
VStack(spacing: 0) {
|
||||
Spacer()
|
||||
Divider()
|
||||
let share = ShareEntitiesView(entities: viewModel.entities, store: viewModel.store, output: output) {
|
||||
shareItems = $0
|
||||
withAnimation {
|
||||
selectedShareOutput = nil
|
||||
}
|
||||
}
|
||||
if #available(iOS 15, *) {
|
||||
share.background(Material.regular)
|
||||
} else {
|
||||
share.background(Color.white)
|
||||
}
|
||||
}
|
||||
.transition(.move(edge: .bottom))
|
||||
private func share(as output: ShareOutput) {
|
||||
selectedShareOutput = output
|
||||
viewModel.prepareForSharing(as: output) { item in
|
||||
selectedShareOutput = nil
|
||||
shareItems = item
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -155,6 +155,12 @@ final class ConsoleViewModel: NSObject, NSFetchedResultsControllerDelegate, Obse
|
||||
table.entities = entities
|
||||
#endif
|
||||
}
|
||||
|
||||
// MARK: - Sharing
|
||||
|
||||
func prepareForSharing(as output: ShareOutput, _ completion: @escaping (ShareItems?) -> Void) {
|
||||
ShareService.share(entities, store: store, as: output, completion)
|
||||
}
|
||||
}
|
||||
|
||||
private func makeFetchRequest(for mode: ConsoleViewModel.Mode) -> NSFetchRequest<NSManagedObject> {
|
||||
|
||||
@@ -30,6 +30,12 @@ struct ShareItems: Identifiable {
|
||||
}
|
||||
|
||||
enum ShareService {
|
||||
private static var task: ShareStoreTask?
|
||||
|
||||
static func share(_ entities: [NSManagedObject], store: LoggerStore, as output: ShareOutput, _ completion: @escaping (ShareItems?) -> Void) {
|
||||
ShareStoreTask(entities: entities, store: store, output: output, completion: completion).start()
|
||||
}
|
||||
|
||||
static func share(_ message: LoggerMessageEntity, as output: ShareOutput) -> ShareItems {
|
||||
share(TextRenderer.share([message]), as: output)
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ import CoreData
|
||||
import SwiftUI
|
||||
import Pulse
|
||||
|
||||
#warning("TODO: make store accesor from BlobEntity private")
|
||||
|
||||
final class ShareStoreTask: ObservableObject {
|
||||
@Published var stage: Stage = .preparing
|
||||
@Published var progress: Float = 0
|
||||
@@ -36,7 +34,7 @@ final class ShareStoreTask: ObservableObject {
|
||||
self.completion = completion
|
||||
}
|
||||
|
||||
func cancel() {
|
||||
func cancel() { // Not yet implemented
|
||||
isCancelled = true
|
||||
completion?(nil)
|
||||
completion = nil
|
||||
@@ -107,9 +105,6 @@ final class ShareStoreTask: ObservableObject {
|
||||
let start = index * indices.count / iterations
|
||||
let end = (index + 1) * indices.count / iterations
|
||||
|
||||
#warning("TEMP")
|
||||
Thread.sleep(forTimeInterval: 0.1)
|
||||
|
||||
for index in start..<end {
|
||||
let job = queue[index]
|
||||
guard let data = job.value.data() else { continue }
|
||||
@@ -133,9 +128,6 @@ final class ShareStoreTask: ObservableObject {
|
||||
continue
|
||||
}
|
||||
|
||||
#warning("TEMP")
|
||||
Thread.sleep(forTimeInterval: 0.1)
|
||||
|
||||
if let task = entity as? NetworkTaskEntity {
|
||||
renderer.render(task, content: content)
|
||||
} else if let message = entity as? LoggerMessageEntity {
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2020–2023 Alexander Grebenyuk (github.com/kean).
|
||||
|
||||
import SwiftUI
|
||||
import CoreData
|
||||
import Pulse
|
||||
import Combine
|
||||
|
||||
struct ShareEntitiesView: View {
|
||||
@StateObject private var viewModel = ShareEntitiesViewModel()
|
||||
private let entities: [NSManagedObject]
|
||||
private let store: LoggerStore
|
||||
private let output: ShareOutput
|
||||
private let completion: (ShareItems?) -> Void
|
||||
|
||||
init(entities: [NSManagedObject], store: LoggerStore, output: ShareOutput, completion: @escaping (ShareItems?) -> Void) {
|
||||
self.entities = entities
|
||||
self.store = store
|
||||
self.output = output
|
||||
self.completion = completion
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .center, spacing: 12) {
|
||||
ProgressView()
|
||||
VStack(alignment: .leading) {
|
||||
Text(viewModel.title)
|
||||
Text(viewModel.details)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
Spacer()
|
||||
if viewModel.isProcessing {
|
||||
Button("Cancel") {
|
||||
viewModel.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.onAppear {
|
||||
viewModel.prepare(entities: entities, store: store, output: output, completion: completion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class ShareEntitiesViewModel: ObservableObject {
|
||||
@Published var title: String = ""
|
||||
@Published var details: String = ""
|
||||
@Published var isProcessing = true
|
||||
|
||||
// TODO: use as binding
|
||||
@Published var shareItem: ShareItems?
|
||||
|
||||
private var isStarted = false
|
||||
private var task: ShareStoreTask?
|
||||
private var cancellables: [AnyCancellable] = []
|
||||
|
||||
init() {}
|
||||
|
||||
func prepare(entities: [NSManagedObject], store: LoggerStore, output: ShareOutput, completion: @escaping (ShareItems?) -> Void) {
|
||||
guard !isStarted else { return }
|
||||
isStarted = true
|
||||
|
||||
let task = ShareStoreTask(entities: entities, store: store, output: output, completion: completion)
|
||||
task.$stage.sink { [weak self] in
|
||||
guard let self = self else { return }
|
||||
switch $0 {
|
||||
case .preparing:
|
||||
self.title = "Preparing Logs..."
|
||||
self.details = "This may take some time"
|
||||
case .rendering:
|
||||
self.title = "Generating \(output.title)..."
|
||||
self.details = "This may take some time"
|
||||
if output == .pdf {
|
||||
self.details = "This operation blocks the app somt time".
|
||||
}
|
||||
case .completed:
|
||||
break
|
||||
}
|
||||
}.store(in: &cancellables)
|
||||
task.start()
|
||||
self.task = task
|
||||
}
|
||||
|
||||
#warning("TODO: implenet cancellation")
|
||||
func cancel() {
|
||||
self.task?.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct ShareEntitiesView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
#if os(iOS)
|
||||
ShareEntitiesView(entities: try! LoggerStore.mock.allMessages(), store: .mock, output: .html) { _ in }
|
||||
#else
|
||||
ShareEntitiesView(entities: try! LoggerStore.mock.allMessages(), store: .mock, output: .html) { _ in }
|
||||
.frame(width: 300, height: 500)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user