This video tutorial demonstrates how to build a macOS menu bar utility app using SwiftUI and system command-line tools.
df (disk free) and du (disk usage) to fetch disk space data, explaining their differences and flags (-H for human-readable, -k for kilobyte).df -k command and parsing it line by line into a Swift DiskInfo model.FormattedDiskInfo model suitable for UI display, including calculations for percentages and formatting for human readability using ByteCountFormatter.MenuBarExtra, showing how to set its style to appear as a window rather than a list of buttons.
df (disk free) command in Terminal to get disk space information (system, available, user data).df Command Usage:df alone provides data in 512-byte blocks, which is not easily readable.df -H (human-readable) displays sizes in gigabytes (GB) or kilobytes (KB).df command caches data and updates roughly once a day, making it quick.du Command Usage:du (disk utility) command performs a proper scan of files and directories, but it takes significantly longer and produces extensive output.-d (depth) and -g (gigabytes) can refine du output to show files larger than a certain size or within a specific directory depth.df -k (kilobyte output) is chosen because it's fast and allows for custom formatting within the app.df does not support JSON output, requiring manual string parsing.man df command can be used to view the documentation (man pages) for the df utility, showing available flags and options.
ViewModels and Models folders to organize code.DiskInfoFetcher class (conforming to ObservableObject) is created to handle data fetching.execute_command function is implemented using Process and Pipe to run shell commands.process.launchPath is set to /bin/zsh (the shell).process.arguments is set to ["-c", command_string] to execute the command string.process.standardOutput is set to a Pipe to capture the command's output.InvalidData and CommandFailed cases.
DiskInfo Struct):DiskInfo struct is created to hold raw parsed data from the df command output.fileSystem, size, used, available (all Int64 in kilobytes), capacity, and mountPoint.parse_output function):df -k is split into lines, with the first line (header) being ignored.DiskInfo object is created from these components, handling potential parsing errors.
FormattedDiskInfo Struct):FormattedDiskInfo struct (conforming to Identifiable) is created for display purposes in SwiftUI.title, size, and totalSize.isSystemVolume, isDataVolume) are added to DiskInfo to easily filter data points (system, available, user data).Array is created to quickly find system and data volumes.parse_diskInfos function transforms DiskInfo array into FormattedDiskInfo array, combining relevant data points for "System," "Available," and "User Data."
getDiskInfo function is created in DiskInfoFetcher to orchestrate the command execution and parsing.async/await and a Task to run the operations in the background, updating @Published properties (diskInfos, error, isLoading) for SwiftUI views to react to.
FormattedDiskInfo is extended with computed properties formattedSize and formattedTotalSize using ByteCountFormatter to convert kilobyte integers into human-readable strings (e.g., "11 GB"). A 1000 factor is added due to the df -k output in kilobytes.DiskInfoRow View:DiskInfoRow view is created to display individual disk info entries.Rectangle inside a GeometryReader, clipped to a Capsule shape for rounded corners.percentage of size relative to totalSize.progressColor computed property assigns different colors (e.g., .blue, .green, .orange) based on the item's title.
DiskInfoListView View:DiskInfoListView is created to display a list of DiskInfoRow elements.ForEach loop within a GroupBox to show the data, providing a structured layout with a "Disk Space Overview" label.listRowSeparator(.hidden) is used to remove default list separators for a cleaner look.DiskInfoChart View:DiskInfoChart view is created to display a pie chart using the Charts framework (requires import Charts).FormattedDiskInfo array as input.SectorMark is used, with angle based on the percentage and angularInset for a donut effect.foregroundStyle is set dynamically based on the item's title (using the same color logic as DiskInfoRow).annotation is added to display the percentage value on each section of the donut chart.
ContentView:ContentView orchestrates the display, embedding the DiskInfoListView and DiskInfoChart below a main "Disk Analyzer" title..task modifier on ContentView's body, ensuring data is loaded when the view appears.do-catch block to update the fetcher.error property if data fetching or parsing fails.
DiskAnalyzerApp.swift) is modified to use MenuBarExtra instead of WindowGroup.MenuBarExtra takes content (the ContentView) and a label (an icon and title for the menu bar). An SF Symbol like "externaldrive" is used for the icon.defaults delete command is used in Terminal to clear user defaults for the app's bundle identifier.menuBarExtraStyle(.window) modifier is applied to the MenuBarExtra to make the pop-up menu look like a standard window rather than a list of buttons, which is better suited for the complex UI.width: 300, height: 400) is added to the ContentView to control the size of the menu bar pop-up.