Skip to content

Commit

Permalink
Merge pull request #34 from boscojwho/bosco/menu-bar-extra
Browse files Browse the repository at this point in the history
Menu bar extra app
  • Loading branch information
boscojwho authored Nov 29, 2023
2 parents bc052f8 + adf2130 commit 4c7a470
Show file tree
Hide file tree
Showing 8 changed files with 225 additions and 21 deletions.
4 changes: 4 additions & 0 deletions Chinotto.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
E4A30AA72B00D24800BE5444 /* ChinottoUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A30AA62B00D24800BE5444 /* ChinottoUITests.swift */; };
E4A30AA92B00D24800BE5444 /* ChinottoUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A30AA82B00D24800BE5444 /* ChinottoUITestsLaunchTests.swift */; };
E4A30AB62B00D32800BE5444 /* Directories.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A30AB52B00D32800BE5444 /* Directories.swift */; };
E4E10D3C2B16CE7A00126C53 /* ChinottoMenuBarApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E10D3B2B16CE7A00126C53 /* ChinottoMenuBarApp.swift */; };
E4F8ECBB2B0453220075AB04 /* DeveloperDiskImagesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F8ECBA2B0453220075AB04 /* DeveloperDiskImagesView.swift */; };
E4F8ECBD2B0453C70075AB04 /* ToolchainsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F8ECBC2B0453C70075AB04 /* ToolchainsView.swift */; };
E4F8ECBF2B0453D10075AB04 /* XcodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F8ECBE2B0453D10075AB04 /* XcodeView.swift */; };
Expand Down Expand Up @@ -90,6 +91,7 @@
E4A30AA62B00D24800BE5444 /* ChinottoUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChinottoUITests.swift; sourceTree = "<group>"; };
E4A30AA82B00D24800BE5444 /* ChinottoUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChinottoUITestsLaunchTests.swift; sourceTree = "<group>"; };
E4A30AB52B00D32800BE5444 /* Directories.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Directories.swift; sourceTree = "<group>"; };
E4E10D3B2B16CE7A00126C53 /* ChinottoMenuBarApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChinottoMenuBarApp.swift; sourceTree = "<group>"; };
E4F8ECBA2B0453220075AB04 /* DeveloperDiskImagesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperDiskImagesView.swift; sourceTree = "<group>"; };
E4F8ECBC2B0453C70075AB04 /* ToolchainsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolchainsView.swift; sourceTree = "<group>"; };
E4F8ECBE2B0453D10075AB04 /* XcodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcodeView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -197,6 +199,7 @@
isa = PBXGroup;
children = (
E4A30A882B00D24700BE5444 /* ChinottoApp.swift */,
E4E10D3B2B16CE7A00126C53 /* ChinottoMenuBarApp.swift */,
E4F8ECCC2B083F440075AB04 /* XcodeVersion.swift */,
E4A30A8A2B00D24700BE5444 /* ContentView.swift */,
E4205D572B020F390026D4A0 /* DirectoriesStorageView.swift */,
Expand Down Expand Up @@ -423,6 +426,7 @@
E4205D582B020F390026D4A0 /* DirectoriesStorageView.swift in Sources */,
E4F8ECBB2B0453220075AB04 /* DeveloperDiskImagesView.swift in Sources */,
E4F8ECCD2B083F440075AB04 /* XcodeVersion.swift in Sources */,
E4E10D3C2B16CE7A00126C53 /* ChinottoMenuBarApp.swift in Sources */,
E4F8ECC12B0453DF0075AB04 /* XCPGDevicesView.swift in Sources */,
E475191D2B03A2E800C360DD /* Subdirectories.swift in Sources */,
E47519212B03AA5F00C360DD /* _CoreSimulatorUserCachesView.swift in Sources */,
Expand Down
13 changes: 12 additions & 1 deletion Chinotto/ChinottoApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,19 @@ import CoreSimulatorUI

@main
struct ChinottoApp: App {
@AppStorage("showMenuBarExtra") private var showMenuBarExtra = true

var body: some Scene {
WindowGroup {
MenuBarExtra(
"Chinotto Menu Bar App",
systemImage: "chart.bar.doc.horizontal",
isInserted: $showMenuBarExtra
) {
ChinottoMenuBarApp()
}
.menuBarExtraStyle(.window)

Window("", id: "Main Window") {
ContentView()
.frame(maxWidth: 1440)
}
Expand Down
44 changes: 44 additions & 0 deletions Chinotto/ChinottoMenuBarApp.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// ChinottoMenuBarApp.swift
// Chinotto
//
// Created by Bosco Ho on 2023-11-28.
//

import SwiftUI

struct ChinottoMenuBarApp: View {
@Environment(\.openWindow) var openWindow
@Environment(\.dismissWindow) var dismissWindow

@State private var directories: [StorageViewModel] = [
.init(directory: .coreSimulator),
.init(directory: .developerDiskImages),
.init(directory: .toolchains),
.init(directory: .xcPGDevices),
.init(directory: .xcTestDevices),
.init(directory: .xcode),
]

var body: some View {
DirectoriesStorageView(viewModels: $directories)
.frame(width: 480, height: 720)
.environment(\.horizontalSizeClass, .compact)
.safeAreaInset(edge: .top) {
HStack {
Text("Chinotto")
.fontWeight(.medium)
.foregroundStyle(.secondary)
Spacer()
Button("Open App...") {
openWindow(id: "Main Window")
dismissWindow()
}
.buttonStyle(.borderedProminent)
.tint(.accentColor)
}
.padding(8)
.background(.regularMaterial)
}
}
}
2 changes: 1 addition & 1 deletion Chinotto/DirectoriesStorageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import SwiftUI

/// Shows the storage consumed for each directory, separately.
struct DirectoriesStorageView: View {

@Environment(\.horizontalSizeClass) var horizontalSizeClass
@Binding var viewModels: [StorageViewModel]

init(viewModels: Binding<[StorageViewModel]>) {
Expand Down
21 changes: 18 additions & 3 deletions Chinotto/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
}
}
}
},
"%@ ago" : {

},
"%@ of %@" : {
"localizations" : {
Expand Down Expand Up @@ -80,6 +83,9 @@
},
"Chinotto" : {

},
"Chinotto Menu Bar App" : {

},
"Core Simulator (Devices)" : {

Expand Down Expand Up @@ -159,9 +165,18 @@
},
"Manually managing this directory is not recommended." : {

},
"Menu Bar" : {

},
"Never" : {

},
"Never Booted" : {

},
"Open App..." : {

},
"Recommended: Manage Toolchains using Xcode's built-in tool (Xcode > Toolchains > Manage Toolchains...)." : {

Expand All @@ -171,12 +186,12 @@
},
"Reset Storage Data..." : {

},
"Select directory data." : {

},
"Show in Finder" : {
"extractionState" : "manual"
},
"Show in Menu Bar (compact view)" : {

},
"Size" : {

Expand Down
10 changes: 10 additions & 0 deletions Chinotto/Preferences/GeneralPreferencesView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,22 @@ import DestructiveActions

struct GeneralPreferencesView: View {

@AppStorage("showMenuBarExtra") private var showMenuBarExtra = true
@AppStorage("preferences.general.deletionBehaviour") var deletionBehaviour: DeletionBehaviour = .moveToTrash

@State private var isPresentingResetStorageDataAlert = false

var body: some View {
Form {
Section {
LabeledContent("Menu Bar") {
Toggle("Show in Menu Bar (compact view)", isOn: $showMenuBarExtra)
}
}

Spacer(minLength: 24)
.frame(height: 24)

Section {
Picker("Deletion Behavior:", selection: $deletionBehaviour) {
ForEach(DeletionBehaviour.allCases) { value in
Expand Down
122 changes: 110 additions & 12 deletions Chinotto/StorageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -172,22 +172,19 @@ final class StorageViewModel: Identifiable {

struct StorageView: View {

@Environment(\.horizontalSizeClass) var horizontalSizeClass
@Bindable var viewModel: StorageViewModel

private var sizeClass: UserInterfaceSizeClass {
horizontalSizeClass ?? .regular
}

var body: some View {
Group {
HStack {
Spacer()
if Date(timeIntervalSinceReferenceDate: viewModel.lastUpdated) == .distantPast {
Text("Last Updated: Never")
.font(.headline)
.fontWeight(.regular)
.foregroundStyle(.secondary)
} else {
Text("Last Updated: \(Date(timeIntervalSinceReferenceDate: viewModel.lastUpdated), style: .relative)")
.font(.headline)
.fontWeight(.regular)
.foregroundStyle(.secondary)
if sizeClass == .regular {
lastUpdated()
}
}
// .offset(y: 8)
Expand All @@ -203,11 +200,17 @@ struct StorageView: View {
} label: {
HStack {
if viewModel.isCalculating {
Text("Calculating...")
if sizeClass == .regular {
Text("Calculating...")
}
ProgressView()
.controlSize(.small)
} else {
Text("Calculate")
if sizeClass == .regular {
Text("Calculate")
} else {
lastUpdated()
}
Image(systemName: "arrow.clockwise")
}
}
Expand All @@ -229,6 +232,18 @@ struct StorageView: View {

@ViewBuilder
private func chartView() -> some View {
switch sizeClass {
case .compact:
compactChartView()
case .regular:
regularChartView()
@unknown default:
regularChartView()
}
}

@ViewBuilder
private func regularChartView() -> some View {
Chart {
Plot {
BarMark(
Expand Down Expand Up @@ -276,6 +291,89 @@ struct StorageView: View {
.chartLegend(.hidden)
.frame(height: 64)
}

@ViewBuilder
private func compactChartView() -> some View {
Chart {
Plot {
BarMark(
x: .value("Directory Size", viewModel.dirSize)
)
.foregroundStyle(viewModel.directory.accentColor)
}
.accessibilityLabel(viewModel.directory.dirName)
.accessibilityValue("\(viewModel.dirSize, specifier: "%.1f") GB")
}
.chartPlotStyle { plotArea in
plotArea
#if os(macOS)
.background(viewModel.directory.accentColor.opacity(0.2))
#else
.background(viewModel.directory.accentColor.opacity(0.2))
#endif
.cornerRadius(8)
}
.chartXAxis {
AxisMarks(
format: .byteCount(style: .memory, allowedUnits: .all, spellsOutZero: true, includesActualByteCount: false),
values: viewModel.axisValues
)
}
.chartXScale(domain: [0, viewModel.volumeTotalCapacity ?? viewModel.dirSize])
.chartXAxisLabel(position: .top) {
switch sizeClass {
case .compact:
EmptyView()
case .regular:
Text("Disk Space Used")
@unknown default:
Text("Disk Space Used")
}
}
.chartYAxis(.hidden)
.chartLegend(.hidden)
.frame(height: 40)
}

@ViewBuilder
private func lastUpdated() -> some View {
switch sizeClass {
case .compact:
if Date(timeIntervalSinceReferenceDate: viewModel.lastUpdated) == .distantPast {
Text("Never")
.font(.headline)
.fontWeight(.regular)
} else {
Text("\(Date(timeIntervalSinceReferenceDate: viewModel.lastUpdated), style: .relative) ago")
.font(.headline)
.fontWeight(.regular)
}
case .regular:
if Date(timeIntervalSinceReferenceDate: viewModel.lastUpdated) == .distantPast {
Text("Last Updated: Never")
.font(.headline)
.fontWeight(.regular)
.foregroundStyle(.secondary)
} else {
Text("Last Updated: \(Date(timeIntervalSinceReferenceDate: viewModel.lastUpdated), style: .relative)")
.font(.headline)
.fontWeight(.regular)
.foregroundStyle(.secondary)
}
@unknown default:
if Date(timeIntervalSinceReferenceDate: viewModel.lastUpdated) == .distantPast {
Text("Never")
.font(.headline)
.fontWeight(.regular)
.foregroundStyle(.secondary)
} else {
Text("\(Date(timeIntervalSinceReferenceDate: viewModel.lastUpdated), style: .relative)")
.font(.headline)
.fontWeight(.regular)
.foregroundStyle(.secondary)
}
}
}
}

#Preview {
Expand Down
30 changes: 26 additions & 4 deletions Chinotto/UnifiedStorageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ import Charts

/// Shows storage consumed for all directories in a unified view.
struct UnifiedStorageView: View {

@Environment(\.horizontalSizeClass) var horizontalSizeClass
@Binding var viewModels: [StorageViewModel]
@State private var isReloading = false

private var sizeClass: UserInterfaceSizeClass {
horizontalSizeClass ?? .regular
}

var body: some View {
GroupBox {
VStack {
Expand Down Expand Up @@ -96,7 +100,14 @@ struct UnifiedStorageView: View {
)
}
.chartXAxisLabel(position: .top) {
Text("Disk Space Used")
switch sizeClass {
case .compact:
EmptyView()
case .regular:
Text("Disk Space Used")
@unknown default:
Text("Disk Space Used")
}
}
.chartPlotStyle { plotArea in
plotArea
Expand All @@ -107,8 +118,19 @@ struct UnifiedStorageView: View {
#endif
.cornerRadius(8)
}
.chartLegend(.visible)
.frame(height: 80)
.chartLegend(chartLegendVisibility)
.frame(height: sizeClass == .compact ? 40 : 80)
}

private var chartLegendVisibility: Visibility {
switch sizeClass {
case .compact:
.hidden
case .regular:
.visible
@unknown default:
.visible
}
}
}

Expand Down

0 comments on commit 4c7a470

Please sign in to comment.