tl;dr: I want to update view so it reflects a variable. The variable changes both when the view is and when its not active.
I am making a status menu app and I need the view to update every second. I want to update the progressValue
var in UtilityToolsView
every so often even when the menu app isn’t selected and when the menu is selected I want the view to reflect the changes of progressValue
. Aside from the view it self, I used this tutorial to make the status menu appear in the top bar (I am new to swiftUI/mac development and even though I am trying to fully understand the code, I don’t fully understand it): Building a macOS Menu Bar App - The Dad Jokes Series (Part 1) - YouTube
I have a function to get the CPU usage which I want to be called every second (or so) and set it to firstValue
, but the view doesn’t update.
ApplicationMenu:
class ApplicationMenu: NSObject {
let menu = NSMenu()
func createMenu() -> NSMenu {
let utilityToolsView = UtilityToolsView()
let topView = NSHostingController(rootView: utilityToolsView)
topView.view.frame.size = CGSize(width: 225, height: 225)
let customMenuItem = NSMenuItem()
customMenuItem.view = topView.view
menu.addItem(customMenuItem)
menu.addItem(NSMenuItem.separator())
return menu;
}
}
AppDelegate + Main:
@main
struct UtilityToolsApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
Settings {
EmptyView()
}
}
}
class AppDelegate: NSObject, NSApplicationDelegate {
static private(set) var instace: AppDelegate!
lazy var statusBarItem = NSStatusBar.system.statusItem(withLength: 20)
let menu = ApplicationMenu()
func applicationDidFinishLaunching(_ notification: Notification) {
AppDelegate.instace = self
let image = NSImage(systemSymbolName: "gearshape.circle", accessibilityDescription: "A gear inside of a circle.")
let config = NSImage.SymbolConfiguration(textStyle: .body, scale: .large)
statusBarItem.button?.image = image?.withSymbolConfiguration(config)!
statusBarItem.button?.imagePosition = .imageLeading
statusBarItem.menu = menu.createMenu()
}
}
And then I have a basic view ( ProgressBar
is a struct that creates the bar. I plan on having multiple):
struct UtilityToolsView: View {
@State var firstValue: Float = 0
var body: some View {
VStack(spacing: 0) {
HStack(alignment: .center, spacing: 15) {
ProgressBar(progress: self.$firstValue)
}.padding(15).padding([.bottom], 0)
}
.padding(5)
Spacer()
}
}
I have tried to add a .task {} with a timer to the view, but it only updates when I don’t have it selected. I thought of defining firstValue outside of the view (updating it periodically there) and then giving it to the view, but I don’t know if that even makes sense and I don’t know how.