From 09da919488e089f0671728aa5fd86cc06036918a Mon Sep 17 00:00:00 2001 From: Alexander Mazanov Date: Wed, 4 Nov 2020 19:56:31 -0500 Subject: [PATCH] If plugin fails to update show error menu --- SwiftBar.xcodeproj/project.pbxproj | 4 ++++ SwiftBar/MenuBar/MenuBarItem.swift | 26 +++++++++++++++++----- SwiftBar/Plugin/ExecutablePlugin.swift | 4 ++-- SwiftBar/Plugin/Plugin.swift | 4 +++- SwiftBar/UI/PluginErrorView.swift | 30 ++++++++++++++++++++++++++ 5 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 SwiftBar/UI/PluginErrorView.swift diff --git a/SwiftBar.xcodeproj/project.pbxproj b/SwiftBar.xcodeproj/project.pbxproj index fb1d28a..0c93d80 100644 --- a/SwiftBar.xcodeproj/project.pbxproj +++ b/SwiftBar.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 398B86C4254DA85300DEA027 /* URL+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398B86C3254DA85300DEA027 /* URL+Extension.swift */; }; 398B86CA254DB5D200DEA027 /* DirectoryObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398B86C9254DB5D200DEA027 /* DirectoryObserver.swift */; }; 398B86CE254DBF2F00DEA027 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398B86CD254DBF2F00DEA027 /* main.swift */; }; + 398DAE7A25537DAF00747D90 /* PluginErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398DAE7925537DAF00747D90 /* PluginErrorView.swift */; }; 39AF776F25461277001D76E5 /* Plugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39AF776E25461277001D76E5 /* Plugin.swift */; }; 39AF7772254612BF001D76E5 /* PluginMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39AF7771254612BF001D76E5 /* PluginMetadata.swift */; }; 39AF7775254613C9001D76E5 /* PluginManger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39AF7774254613C9001D76E5 /* PluginManger.swift */; }; @@ -52,6 +53,7 @@ 398B86C3254DA85300DEA027 /* URL+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Extension.swift"; sourceTree = ""; }; 398B86C9254DB5D200DEA027 /* DirectoryObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectoryObserver.swift; sourceTree = ""; }; 398B86CD254DBF2F00DEA027 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; + 398DAE7925537DAF00747D90 /* PluginErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginErrorView.swift; sourceTree = ""; }; 39AF776E25461277001D76E5 /* Plugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Plugin.swift; sourceTree = ""; }; 39AF7771254612BF001D76E5 /* PluginMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginMetadata.swift; sourceTree = ""; }; 39AF7774254613C9001D76E5 /* PluginManger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginManger.swift; sourceTree = ""; }; @@ -129,6 +131,7 @@ 39641EA7254E0DFD00713DAF /* Helpers */, 39641EA0254DD32100713DAF /* AboutPluginView.swift */, 39641EA4254E096200713DAF /* PreferencesView.swift */, + 398DAE7925537DAF00747D90 /* PluginErrorView.swift */, ); path = UI; sourceTree = ""; @@ -299,6 +302,7 @@ 39AF7799254C7796001D76E5 /* String+Emoji.swift in Sources */, 39641EA9254E0E0B00713DAF /* EnumPicker.swift in Sources */, 39AF7775254613C9001D76E5 /* PluginManger.swift in Sources */, + 398DAE7A25537DAF00747D90 /* PluginErrorView.swift in Sources */, 39AF7778254613FB001D76E5 /* ExecutablePlugin.swift in Sources */, 39AF77842547750E001D76E5 /* App.swift in Sources */, 39641EA1254DD32100713DAF /* AboutPluginView.swift in Sources */, diff --git a/SwiftBar/MenuBar/MenuBarItem.swift b/SwiftBar/MenuBar/MenuBarItem.swift index 224980b..0147cca 100644 --- a/SwiftBar/MenuBar/MenuBarItem.swift +++ b/SwiftBar/MenuBar/MenuBarItem.swift @@ -116,8 +116,8 @@ extension MenubarItem { let quitItem = NSMenuItem(title: "Quit SwiftBar", action: #selector(quit), keyEquivalent: "q") let runInTerminalItem = NSMenuItem(title: "Run in Terminal...", action: #selector(runInTerminal), keyEquivalent: "") let disablePluginItem = NSMenuItem(title: "Disable Plugin", action: #selector(disablePlugin), keyEquivalent: "") - - [refreshAllItem,enableAllItem,disableAllItem,preferencesItem,openPluginFolderItem,changePluginFolderItem,getPluginsItem,quitItem,disablePluginItem,aboutItem,aboutSwiftBarItem,runInTerminalItem].forEach{$0.target = self} + let showErrorItem = NSMenuItem(title: "Show Error", action: #selector(showError), keyEquivalent: "") + [refreshAllItem,enableAllItem,disableAllItem,preferencesItem,openPluginFolderItem,changePluginFolderItem,getPluginsItem,quitItem,disablePluginItem,aboutItem,aboutSwiftBarItem,runInTerminalItem,showErrorItem].forEach{$0.target = self} menu.addItem(refreshAllItem) menu.addItem(enableAllItem) @@ -143,6 +143,9 @@ extension MenubarItem { // default plugin menu items statusBarMenu.addItem(NSMenuItem.separator()) statusBarMenu.addItem(lastUpdatedMenuItem) + if plugin?.error != nil { + statusBarMenu.addItem(showErrorItem) + } statusBarMenu.addItem(runInTerminalItem) statusBarMenu.addItem(disablePluginItem) if plugin?.metadata?.isEmpty == false { @@ -189,6 +192,15 @@ extension MenubarItem { NSApp.terminate(self) } + @objc func showError() { + guard let plugin = plugin, plugin.error != nil else {return} + let popover = NSPopover() + popover.behavior = .transient + popover.contentViewController = NSHostingController(rootView: PluginErrorView(plugin: plugin)) + popover.show(relativeTo: barItem.button!.bounds, of: barItem.button!, preferredEdge: .minY) + popover.contentViewController?.view.window?.becomeKey() + } + @objc func runInTerminal() { guard let scriptPath = plugin?.file else {return} App.runInTerminal(script: scriptPath) @@ -366,13 +378,17 @@ extension MenubarItem { ]), fullTitle) } + func itemActionSelector(params: MenuLineParameters) -> Selector? { + return params.href != nil ? #selector(performMenuItemHREFAction): + params.bash != nil ? #selector(performMenuItemBashAction): + params.refresh ? #selector(performMenuItemRefreshAction): nil + } + func buildMenuItem(params: MenuLineParameters) -> NSMenuItem? { guard params.dropdown else {return nil} let item = NSMenuItem(title: params.title, - action: params.href != nil ? #selector(performMenuItemHREFAction): - params.bash != nil ? #selector(performMenuItemBashAction): - params.refresh ? #selector(performMenuItemRefreshAction): nil, + action: itemActionSelector(params: params), keyEquivalent: "") item.representedObject = params let title = atributedTitle(with: params) diff --git a/SwiftBar/Plugin/ExecutablePlugin.swift b/SwiftBar/Plugin/ExecutablePlugin.swift index 0f30e35..0093168 100644 --- a/SwiftBar/Plugin/ExecutablePlugin.swift +++ b/SwiftBar/Plugin/ExecutablePlugin.swift @@ -23,7 +23,7 @@ class ExecutablePlugin: Plugin { contentUpdatePublisher.send("") } } - var error: String? + var error: ShellOutError? let queue = OperationQueue() @@ -104,7 +104,7 @@ class ExecutablePlugin: Plugin { } catch { guard let error = error as? ShellOutError else {return nil} os_log("Failed to execute script\n%s\n%s", log: Log.plugin, type:.error, file, error.message) - self.error = error.message + self.error = error } return nil } diff --git a/SwiftBar/Plugin/Plugin.swift b/SwiftBar/Plugin/Plugin.swift index a04d7eb..7f1bc9d 100644 --- a/SwiftBar/Plugin/Plugin.swift +++ b/SwiftBar/Plugin/Plugin.swift @@ -1,4 +1,5 @@ import Foundation +import ShellOut enum PluginType { case Executable @@ -15,8 +16,9 @@ protocol Plugin { var enabled: Bool {get} var metadata: PluginMetadata? { get } var updateInterval: Double {get} + var lastUpdated: Date? {get set} var content: String? {get set} - var error: String? {get set} + var error: ShellOutError? {get set} func refresh() func terminate() func invoke(params: [String]) -> String? diff --git a/SwiftBar/UI/PluginErrorView.swift b/SwiftBar/UI/PluginErrorView.swift new file mode 100644 index 0000000..1d5989f --- /dev/null +++ b/SwiftBar/UI/PluginErrorView.swift @@ -0,0 +1,30 @@ +import SwiftUI + +struct PluginErrorView: View { + var plugin: Plugin + var lastUpdateDate: String { + let date = plugin.lastUpdated ?? Date.distantPast + let formatter = DateFormatter() + formatter.dateStyle = .medium + formatter.timeStyle = .medium + return formatter.string(from: date) + } + var body: some View { + ScrollView(showsIndicators: true) { + Form { + LabelView(label: "Plugin:", value: plugin.name) + LabelView(label: "File:", value: plugin.file) + LabelView(label: "Runned at:", value: lastUpdateDate) + LabelView(label: "Error:", value: plugin.error?.message ?? "none") + LabelView(label: "Script Output:", value:plugin.error?.output ?? "none") + }.padding() + .frame(width: 500) + } + } +} + +struct PluginErrorView_Previews: PreviewProvider { + static var previews: some View { + PluginErrorView(plugin: ExecutablePlugin(fileURL: URL(string:"/Users/melonamin/Downloads/bitbar-scripts-copy/mounted.5s.sh")!)) + } +}