From 9daae8957ac6a54dda8b34d27638cdf0a3b2cfec Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Sun, 15 Mar 2020 14:36:07 -0700 Subject: [PATCH] Add notice if agent isn't running (#47) * Add agent checker * Check on foreground --- Secretive.xcodeproj/project.pbxproj | 8 +++++ Secretive/AppDelegate.swift | 8 +++-- .../Controllers/AgentStatusChecker.swift | 33 +++++++++++++++++ .../PreviewAgentStatusChecker.swift | 12 +++++++ Secretive/Views/ContentView.swift | 35 +++++++++++++++---- 5 files changed, 87 insertions(+), 9 deletions(-) create mode 100644 Secretive/Controllers/AgentStatusChecker.swift create mode 100644 Secretive/Preview Content/PreviewAgentStatusChecker.swift diff --git a/Secretive.xcodeproj/project.pbxproj b/Secretive.xcodeproj/project.pbxproj index 45eccf9..bace006 100644 --- a/Secretive.xcodeproj/project.pbxproj +++ b/Secretive.xcodeproj/project.pbxproj @@ -33,6 +33,8 @@ 50731666241DF8660023809E /* Updater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50731665241DF8660023809E /* Updater.swift */; }; 50731669241E00C20023809E /* NoticeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50731668241E00C20023809E /* NoticeView.swift */; }; 508A58AA241E06B40069DC07 /* PreviewUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58A9241E06B40069DC07 /* PreviewUpdater.swift */; }; + 508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */; }; + 508A58B5241ED48F0069DC07 /* PreviewAgentStatusChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A58B4241ED48F0069DC07 /* PreviewAgentStatusChecker.swift */; }; 5099A02423FD2AAA0062B6F2 /* CreateSecretView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02323FD2AAA0062B6F2 /* CreateSecretView.swift */; }; 5099A02723FE34FA0062B6F2 /* SmartCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02623FE34FA0062B6F2 /* SmartCard.swift */; }; 5099A02923FE35240062B6F2 /* SmartCardStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5099A02823FE35240062B6F2 /* SmartCardStore.swift */; }; @@ -186,6 +188,8 @@ 50731668241E00C20023809E /* NoticeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeView.swift; sourceTree = ""; }; 508A58A9241E06B40069DC07 /* PreviewUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewUpdater.swift; sourceTree = ""; }; 508A58AB241E121B0069DC07 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = ""; }; + 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgentStatusChecker.swift; sourceTree = ""; }; + 508A58B4241ED48F0069DC07 /* PreviewAgentStatusChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewAgentStatusChecker.swift; sourceTree = ""; }; 5099A02323FD2AAA0062B6F2 /* CreateSecretView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateSecretView.swift; sourceTree = ""; }; 5099A02623FE34FA0062B6F2 /* SmartCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartCard.swift; sourceTree = ""; }; 5099A02823FE35240062B6F2 /* SmartCardStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartCardStore.swift; sourceTree = ""; }; @@ -322,6 +326,7 @@ 50617D8923FCE48E0099B055 /* Preview Assets.xcassets */, 50617DD123FCEFA90099B055 /* PreviewStore.swift */, 508A58A9241E06B40069DC07 /* PreviewUpdater.swift */, + 508A58B4241ED48F0069DC07 /* PreviewAgentStatusChecker.swift */, ); path = "Preview Content"; sourceTree = ""; @@ -412,6 +417,7 @@ isa = PBXGroup; children = ( 50731665241DF8660023809E /* Updater.swift */, + 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */, ); path = Controllers; sourceTree = ""; @@ -768,6 +774,7 @@ 50C385A9240B636500AF2719 /* SetupView.swift in Sources */, 50617D8523FCE48E0099B055 /* ContentView.swift in Sources */, 50617DD223FCEFA90099B055 /* PreviewStore.swift in Sources */, + 508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */, 50C385A52407A76D00AF2719 /* SecretDetailView.swift in Sources */, 5099A02423FD2AAA0062B6F2 /* CreateSecretView.swift in Sources */, 50731666241DF8660023809E /* Updater.swift in Sources */, @@ -775,6 +782,7 @@ 50BB046B2418AAAE00D6E079 /* EmptyStoreView.swift in Sources */, 50731669241E00C20023809E /* NoticeView.swift in Sources */, 50617D8323FCE48E0099B055 /* AppDelegate.swift in Sources */, + 508A58B5241ED48F0069DC07 /* PreviewAgentStatusChecker.swift in Sources */, 508A58AA241E06B40069DC07 /* PreviewUpdater.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Secretive/AppDelegate.swift b/Secretive/AppDelegate.swift index 62c863d..b40feac 100644 --- a/Secretive/AppDelegate.swift +++ b/Secretive/AppDelegate.swift @@ -14,10 +14,10 @@ class AppDelegate: NSObject, NSApplicationDelegate { return list }() let updater = Updater() + let agentStatusChecker = AgentStatusChecker() func applicationDidFinishLaunching(_ aNotification: Notification) { - - let contentView = ContentView(storeList: storeList, updater: updater) + let contentView = ContentView(storeList: storeList, updater: updater, agentStatusChecker: agentStatusChecker, runSetupBlock: { self.runSetup(sender: nil) }) // Create the window and set the content view. window = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 480, height: 300), @@ -38,6 +38,10 @@ class AppDelegate: NSObject, NSApplicationDelegate { runSetupIfNeeded() } + func applicationDidBecomeActive(_ notification: Notification) { + agentStatusChecker.check() + } + @IBAction func add(sender: AnyObject?) { var addWindow: NSWindow! let addView = CreateSecretView(store: storeList.modifiableStore!) { diff --git a/Secretive/Controllers/AgentStatusChecker.swift b/Secretive/Controllers/AgentStatusChecker.swift new file mode 100644 index 0000000..02b7f84 --- /dev/null +++ b/Secretive/Controllers/AgentStatusChecker.swift @@ -0,0 +1,33 @@ +import Foundation +import Combine +import AppKit + +protocol AgentStatusCheckerProtocol: ObservableObject { + var running: Bool { get } +} + +class AgentStatusChecker: ObservableObject, AgentStatusCheckerProtocol { + + @Published var running: Bool = false + + init() { + check() + } + + func check() { + running = secretAgentProcess != nil + } + + var secretAgentProcess: NSRunningApplication? { + NSRunningApplication.runningApplications(withBundleIdentifier: Constants.secretAgentAppID).first + } + +} + +extension AgentStatusChecker { + + enum Constants { + static let secretAgentAppID = "com.maxgoedjen.Secretive.SecretAgent" + } + +} diff --git a/Secretive/Preview Content/PreviewAgentStatusChecker.swift b/Secretive/Preview Content/PreviewAgentStatusChecker.swift new file mode 100644 index 0000000..b2554d7 --- /dev/null +++ b/Secretive/Preview Content/PreviewAgentStatusChecker.swift @@ -0,0 +1,12 @@ +import Foundation +import Combine + +class PreviewAgentStatusChecker: AgentStatusCheckerProtocol { + + let running: Bool + + init(running: Bool = true) { + self.running = running + } + +} diff --git a/Secretive/Views/ContentView.swift b/Secretive/Views/ContentView.swift index 62ec061..730b65b 100644 --- a/Secretive/Views/ContentView.swift +++ b/Secretive/Views/ContentView.swift @@ -1,10 +1,12 @@ import SwiftUI import SecretKit -struct ContentView: View { +struct ContentView: View { @ObservedObject var storeList: SecretStoreList @ObservedObject var updater: UpdaterType + @ObservedObject var agentStatusChecker: AgentStatusCheckerType + var runSetupBlock: (() -> Void)? @State fileprivate var active: AnySecret.ID? @State fileprivate var showingDeletion = false @@ -15,6 +17,9 @@ struct ContentView: View { if updater.update != nil { updateNotice() } + if !agentStatusChecker.running { + agentNotice() + } NavigationView { List(selection: $active) { ForEach(storeList.stores) { store in @@ -82,6 +87,12 @@ struct ContentView: View { }) } + func agentNotice() -> some View { + NoticeView(text: "Secret Agent isn't running. Run setup again to fix.", severity: .advisory, actionTitle: "Run Setup") { + self.runSetupBlock?() + } + } + func delete(secret: SecretType) { deletingSecret = AnySecret(secret) self.showingDeletion = true @@ -110,12 +121,22 @@ fileprivate enum Constants { struct ContentView_Previews: PreviewProvider { static var previews: some View { Group { - ContentView(storeList: Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]), updater: PreviewUpdater()) - ContentView(storeList: Preview.storeList(stores: [Preview.Store()], modifiableStores: [Preview.StoreModifiable()]), updater: PreviewUpdater()) - ContentView(storeList: Preview.storeList(stores: [Preview.Store()]), updater: PreviewUpdater()) - ContentView(storeList: Preview.storeList(modifiableStores: [Preview.StoreModifiable()]), updater: PreviewUpdater()) - ContentView(storeList: Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]), updater: PreviewUpdater(update: .advisory)) - ContentView(storeList: Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]), updater: PreviewUpdater(update: .critical)) + ContentView(storeList: Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], + modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]), + updater: PreviewUpdater(), + agentStatusChecker: PreviewAgentStatusChecker()) + ContentView(storeList: Preview.storeList(stores: [Preview.Store()], modifiableStores: [Preview.StoreModifiable()]), updater: PreviewUpdater(), + agentStatusChecker: PreviewAgentStatusChecker()) + ContentView(storeList: Preview.storeList(stores: [Preview.Store()]), updater: PreviewUpdater(), + agentStatusChecker: PreviewAgentStatusChecker()) + ContentView(storeList: Preview.storeList(modifiableStores: [Preview.StoreModifiable()]), updater: PreviewUpdater(), + agentStatusChecker: PreviewAgentStatusChecker()) + ContentView(storeList: Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]), updater: PreviewUpdater(update: .advisory), + agentStatusChecker: PreviewAgentStatusChecker()) + ContentView(storeList: Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]), updater: PreviewUpdater(update: .critical), + agentStatusChecker: PreviewAgentStatusChecker()) + ContentView(storeList: Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]), updater: PreviewUpdater(update: .critical), + agentStatusChecker: PreviewAgentStatusChecker(running: false)) } } }