added macOSMenuBar
This commit is contained in:
parent
efee4afc8d
commit
534e615919
9 changed files with 160 additions and 35 deletions
|
|
@ -8,7 +8,7 @@
|
||||||
</array>
|
</array>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>$(APP_GROUP_IDENTIFIER)</string>
|
<string>group.com.hackclub.burrow</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
69
Apple/App/Menu/MenuView.swift
Normal file
69
Apple/App/Menu/MenuView.swift
Normal 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() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ import Foundation
|
||||||
import NetworkExtension
|
import NetworkExtension
|
||||||
|
|
||||||
extension Tunnel {
|
extension Tunnel {
|
||||||
|
|
||||||
enum Status: CustomStringConvertible, Equatable, Hashable {
|
enum Status: CustomStringConvertible, Equatable, Hashable {
|
||||||
case unknown
|
case unknown
|
||||||
case permissionRequired
|
case permissionRequired
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
|
||||||
Text(verbatim: tunnel.status.description)
|
|
||||||
switch tunnel.status {
|
|
||||||
case .connected:
|
|
||||||
Button("Disconnect", action: stop)
|
|
||||||
case .permissionRequired:
|
|
||||||
Button("Allow", action: configure)
|
|
||||||
case .disconnected:
|
|
||||||
Button("Start", action: start)
|
|
||||||
default:
|
|
||||||
EmptyView()
|
EmptyView()
|
||||||
}
|
// VStack {
|
||||||
}
|
// Text(verbatim: tunnel.status.description)
|
||||||
.task { await tunnel.update() }
|
// switch tunnel.status {
|
||||||
.padding()
|
// case .connected:
|
||||||
|
// Button("Disconnect", action: stop)
|
||||||
|
// case .permissionRequired:
|
||||||
|
// Button("Allow", action: configure)
|
||||||
|
// case .disconnected:
|
||||||
|
// Button("Start", action: start)
|
||||||
|
// default:
|
||||||
|
// EmptyView()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// .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() }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 */,
|
||||||
|
|
@ -329,6 +341,10 @@
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = D020F66229E4A6E5002790F6 /* NetworkExtension.xcconfig */;
|
baseConfigurationReference = D020F66229E4A6E5002790F6 /* NetworkExtension.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
DEVELOPMENT_TEAM = P6PV2R9443;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = Burrow;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Hack Club";
|
||||||
|
"PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.hackclub.burrow.network;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
|
|
@ -336,6 +352,10 @@
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = D020F66229E4A6E5002790F6 /* NetworkExtension.xcconfig */;
|
baseConfigurationReference = D020F66229E4A6E5002790F6 /* NetworkExtension.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
DEVELOPMENT_TEAM = P6PV2R9443;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = Burrow;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Hack Club";
|
||||||
|
"PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.hackclub.burrow.network;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>$(INFOPLIST_KEY_CFBundleDisplayName)</string>
|
|
||||||
<key>NSExtension</key>
|
<key>NSExtension</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSExtensionPointIdentifier</key>
|
<key>NSExtensionPointIdentifier</key>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
</array>
|
</array>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>$(APP_GROUP_IDENTIFIER)</string>
|
<string>group.com.hackclub.burrow</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue