Added initial menu bar to macOS

This commit is contained in:
SerenityUX 2023-06-23 20:19:10 -04:00 committed by Conrad Kramer
parent 923bc9511d
commit 5438542284
5 changed files with 149 additions and 31 deletions

View file

@ -4,14 +4,50 @@ import SwiftUI
@main @main
@MainActor @MainActor
struct BurrowApp: App { struct BurrowApp: App {
//To connect to the App Delegate
@NSApplicationDelegateAdaptor(AppDelegate.self) var delegate
var body: some Scene {
WindowGroup {
TunnelView()
}
}
}
@MainActor
class AppDelegate: NSObject, NSApplicationDelegate {
static let tunnel = Tunnel { manager, proto in static let tunnel = Tunnel { manager, proto in
proto.serverAddress = "hackclub.com" proto.serverAddress = "hackclub.com"
manager.localizedDescription = "Burrow" manager.localizedDescription = "Burrow"
} }
var body: some Scene { var statusItem: NSStatusItem?
WindowGroup { var popOver = NSPopover()
TunnelView(tunnel: Self.tunnel) func applicationDidFinishLaunching(_ notification: Notification) {
let menuView = MenuView(tunnel: AppDelegate.tunnel)
// Creating apopOver
popOver.behavior = .transient
popOver.animates = true
popOver.contentViewController = NSViewController()
popOver.contentViewController?.view = NSHostingView(rootView: menuView)
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
// Safe Check if status Button is Available or not...
if let menuButton = statusItem?.button {
let icon = "network.badge.shield.half.filled"
menuButton.image = NSImage(systemSymbolName: icon, accessibilityDescription: nil)
menuButton.action = #selector(menuButtonToggle)
}
}
@objc func menuButtonToggle() {
if let menuButton = statusItem?.button {
self.popOver.show(relativeTo: menuButton.bounds, of: menuButton, preferredEdge: NSRectEdge.minY)
} }
} }
} }

View file

@ -0,0 +1,69 @@
//
// MenuView.swift
// App
//
// Created by Thomas Stubblefield on 5/13/23.
//
import SwiftUI
struct MenuView: View {
@State private var isToggled = false
@ObservedObject var tunnel: Tunnel
private func start() {
do {
try tunnel.start()
} catch {
print(error)
}
}
private func stop() {
tunnel.stop()
}
private func configure() {
Task { try await tunnel.configure() }
}
var body: some View {
VStack {
HStack {
Text("Burrow")
.fontWeight(.bold)
Spacer()
Toggle("", isOn: $isToggled)
.toggleStyle(SwitchToggleStyle(tint: .blue))
.onChange(of: isToggled) { value in
if value {
start()
} else {
stop()
}
print("Toggle value: \(value)")
}
}
Divider()
switch tunnel.status {
case .permissionRequired:
VStack(alignment: .leading) {
Text("Burrow requires additional permissions to function optimally on your machine. Please grant the necessary permissions to ensure smooth operation.")
.font(.caption)
.truncationMode(.tail)
Button("Grant Permissions", action: configure)
}
default:
Text("Burrow is equipped with the necessary permissions to operate seamlessly on your device.")
.font(.caption)
}
}
.frame(width: 250)
.padding(16)
.task { await tunnel.update() }
}
}

View file

@ -1,35 +1,36 @@
import SwiftUI import SwiftUI
struct TunnelView: View { struct TunnelView: View {
@ObservedObject var tunnel: Tunnel // @ObservedObject var tunnel: Tunnel
var body: some View { var body: some View {
VStack { EmptyView()
Text(verbatim: tunnel.status.description) // VStack {
switch tunnel.status { // Text(verbatim: tunnel.status.description)
case .connected: // switch tunnel.status {
Button("Disconnect", action: stop) // case .connected:
case .permissionRequired: // Button("Disconnect", action: stop)
Button("Allow", action: configure) // case .permissionRequired:
case .disconnected: // Button("Allow", action: configure)
Button("Start", action: start) // case .disconnected:
default: // Button("Start", action: start)
EmptyView() // default:
} // EmptyView()
} // }
.task { await tunnel.update() } // }
.padding() // .task { await tunnel.update() }
// .padding()
} }
private func start() { // private func start() {
try? tunnel.start() // try? tunnel.start()
} // }
//
private func stop() { // private func stop() {
tunnel.stop() // tunnel.stop()
} // }
//
private func configure() { // private func configure() {
Task { try await tunnel.configure() } // Task { try await tunnel.configure() }
} // }
} }

View file

@ -7,6 +7,7 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
43AA26D82A10004900F14CE6 /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43AA26D72A10004900F14CE6 /* MenuView.swift */; };
D020F65829E4A697002790F6 /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D020F65729E4A697002790F6 /* PacketTunnelProvider.swift */; }; D020F65829E4A697002790F6 /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D020F65729E4A697002790F6 /* PacketTunnelProvider.swift */; };
D020F65D29E4A697002790F6 /* BurrowNetworkExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D020F65329E4A697002790F6 /* BurrowNetworkExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; D020F65D29E4A697002790F6 /* BurrowNetworkExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D020F65329E4A697002790F6 /* BurrowNetworkExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
D05B9F7629E39EEC008CB1F9 /* BurrowApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05B9F7529E39EEC008CB1F9 /* BurrowApp.swift */; }; D05B9F7629E39EEC008CB1F9 /* BurrowApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05B9F7529E39EEC008CB1F9 /* BurrowApp.swift */; };
@ -44,6 +45,7 @@
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
43AA26D72A10004900F14CE6 /* MenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuView.swift; sourceTree = "<group>"; };
D020F63D29E4A1FF002790F6 /* Identity.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Identity.xcconfig; sourceTree = "<group>"; }; D020F63D29E4A1FF002790F6 /* Identity.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Identity.xcconfig; sourceTree = "<group>"; };
D020F64029E4A1FF002790F6 /* Compiler.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Compiler.xcconfig; sourceTree = "<group>"; }; D020F64029E4A1FF002790F6 /* Compiler.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Compiler.xcconfig; sourceTree = "<group>"; };
D020F64229E4A1FF002790F6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; D020F64229E4A1FF002790F6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@ -90,6 +92,14 @@
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
43AA26D62A0FFFD000F14CE6 /* Menu */ = {
isa = PBXGroup;
children = (
43AA26D72A10004900F14CE6 /* MenuView.swift */,
);
path = Menu;
sourceTree = "<group>";
};
D020F63C29E4A1FF002790F6 /* Configuration */ = { D020F63C29E4A1FF002790F6 /* Configuration */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -137,6 +147,7 @@
D05B9F7429E39EEC008CB1F9 /* App */ = { D05B9F7429E39EEC008CB1F9 /* App */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
43AA26D62A0FFFD000F14CE6 /* Menu */,
D05B9F7529E39EEC008CB1F9 /* BurrowApp.swift */, D05B9F7529E39EEC008CB1F9 /* BurrowApp.swift */,
D05B9F7729E39EEC008CB1F9 /* TunnelView.swift */, D05B9F7729E39EEC008CB1F9 /* TunnelView.swift */,
D0B98FC629FDC5B5004E7149 /* Tunnel.swift */, D0B98FC629FDC5B5004E7149 /* Tunnel.swift */,
@ -299,6 +310,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
D0BCC6082A0981FE00AD070D /* Tunnel.swift in Sources */, D0BCC6082A0981FE00AD070D /* Tunnel.swift in Sources */,
43AA26D82A10004900F14CE6 /* MenuView.swift in Sources */,
D05B9F7829E39EEC008CB1F9 /* TunnelView.swift in Sources */, D05B9F7829E39EEC008CB1F9 /* TunnelView.swift in Sources */,
D0BCC5FF2A086E1C00AD070D /* Status.swift in Sources */, D0BCC5FF2A086E1C00AD070D /* Status.swift in Sources */,
D05B9F7629E39EEC008CB1F9 /* BurrowApp.swift in Sources */, D05B9F7629E39EEC008CB1F9 /* BurrowApp.swift in Sources */,