From 257d45197bc87fcb587dfae46bb57ca73dc7dc76 Mon Sep 17 00:00:00 2001 From: kean Date: Sat, 14 Jan 2023 15:34:39 -0500 Subject: [PATCH] Remove ShareEntitiesView --- Pulse.xcodeproj/project.pbxproj | 4 - .../Features/Console/ConsoleView-ios.swift | 40 +++---- .../Features/Console/ConsoleViewModel.swift | 6 ++ Sources/PulseUI/Helpers/ShareItems.swift | 6 ++ Sources/PulseUI/Helpers/ShareStoreTask.swift | 10 +- Sources/PulseUI/Views/ShareEntitiesView.swift | 102 ------------------ 6 files changed, 29 insertions(+), 139 deletions(-) delete mode 100644 Sources/PulseUI/Views/ShareEntitiesView.swift diff --git a/Pulse.xcodeproj/project.pbxproj b/Pulse.xcodeproj/project.pbxproj index e7472c49..62a9c9a1 100644 --- a/Pulse.xcodeproj/project.pbxproj +++ b/Pulse.xcodeproj/project.pbxproj @@ -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 = ""; }; 0C9F04FF2884F34A0035239F /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 0C9F05012884F34A0035239F /* Pulse_Demo_macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Pulse_Demo_macOS.entitlements; sourceTree = ""; }; - 0CD7E0BA297326EC00A255B7 /* ShareEntitiesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareEntitiesView.swift; sourceTree = ""; }; 0CD7E0BC29732C8E00A255B7 /* ShareStoreTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareStoreTask.swift; sourceTree = ""; }; 0CDC3BE92970FA47003BD1FF /* ConsoleSearchListSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsoleSearchListSelectionView.swift; sourceTree = ""; }; 0CDC3BEC2971B936003BD1FF /* ConsoleSearchLogLevelsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsoleSearchLogLevelsCell.swift; sourceTree = ""; }; @@ -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 */, diff --git a/Sources/PulseUI/Features/Console/ConsoleView-ios.swift b/Sources/PulseUI/Features/Console/ConsoleView-ios.swift index 6f04301c..568d4f98 100644 --- a/Sources/PulseUI/Features/Console/ConsoleView-ios.swift +++ b/Sources/PulseUI/Features/Console/ConsoleView-ios.swift @@ -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 } } diff --git a/Sources/PulseUI/Features/Console/ConsoleViewModel.swift b/Sources/PulseUI/Features/Console/ConsoleViewModel.swift index cdb6d8c5..5b7aa866 100644 --- a/Sources/PulseUI/Features/Console/ConsoleViewModel.swift +++ b/Sources/PulseUI/Features/Console/ConsoleViewModel.swift @@ -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 { diff --git a/Sources/PulseUI/Helpers/ShareItems.swift b/Sources/PulseUI/Helpers/ShareItems.swift index 78bfbc05..b857ff3d 100644 --- a/Sources/PulseUI/Helpers/ShareItems.swift +++ b/Sources/PulseUI/Helpers/ShareItems.swift @@ -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) } diff --git a/Sources/PulseUI/Helpers/ShareStoreTask.swift b/Sources/PulseUI/Helpers/ShareStoreTask.swift index 1cf07653..c535e2ec 100644 --- a/Sources/PulseUI/Helpers/ShareStoreTask.swift +++ b/Sources/PulseUI/Helpers/ShareStoreTask.swift @@ -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.. 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