-
Notifications
You must be signed in to change notification settings - Fork 274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(apple): Handle network changes reliably on macOS and iOS #4133
Changes from all commits
e77d5ae
b78d67a
1363672
34ba208
7953bcc
d464659
36c1bc8
828e062
2de10df
91b9a2f
5ff2898
feb51f9
b81821a
13b3765
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,7 +29,8 @@ struct FirezoneApp: App { | |
StateObject( | ||
wrappedValue: AskPermissionViewModel( | ||
tunnelStore: appStore.tunnelStore, | ||
sessionNotificationHelper: SessionNotificationHelper(logger: appStore.logger, authStore: appStore.authStore) | ||
sessionNotificationHelper: SessionNotificationHelper( | ||
logger: appStore.logger, tunnelStore: appStore.tunnelStore) | ||
) | ||
) | ||
appDelegate.appStore = appStore | ||
|
@@ -47,7 +48,7 @@ struct FirezoneApp: App { | |
} | ||
#else | ||
WindowGroup( | ||
"Firezone (VPN Permission)", | ||
"Welcome to Firezone", | ||
id: AppStore.WindowDefinition.askPermission.identifier | ||
) { | ||
AskPermissionView(model: askPermissionViewModel) | ||
|
@@ -74,31 +75,24 @@ struct FirezoneApp: App { | |
private var isAppLaunched = false | ||
private var menuBar: MenuBar? | ||
|
||
public var appStore: AppStore? { | ||
didSet { | ||
if self.isAppLaunched { | ||
// This is not expected to happen because appStore | ||
// should be set before the app finishes launching. | ||
// This code is only a contingency. | ||
if let appStore = self.appStore { | ||
self.menuBar = MenuBar(appStore: appStore) | ||
} | ||
} | ||
} | ||
} | ||
public var appStore: AppStore? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "store" here means some persistent variable storage, it's not related to the Apple App Store package manager, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I was confused by that too at first. That's correct. It could probably use a rename. |
||
|
||
func applicationDidFinishLaunching(_: Notification) { | ||
self.isAppLaunched = true | ||
if let appStore = self.appStore { | ||
self.menuBar = MenuBar(appStore: appStore) | ||
self.menuBar = MenuBar( | ||
tunnelStore: appStore.tunnelStore, | ||
settingsViewModel: appStore.settingsViewModel, | ||
logger: appStore.logger | ||
) | ||
} | ||
|
||
// SwiftUI will show the first window group, so close it on launch | ||
_ = AppStore.WindowDefinition.allCases.map { $0.window()?.close() } | ||
} | ||
|
||
func applicationWillTerminate(_: Notification) { | ||
self.appStore?.authStore.cancelSignIn() | ||
self.appStore?.tunnelStore.cancelSignIn() | ||
} | ||
} | ||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,14 +33,13 @@ public final class AskPermissionViewModel: ObservableObject { | |
self.tunnelStore = tunnelStore | ||
self.sessionNotificationHelper = sessionNotificationHelper | ||
|
||
tunnelStore.$tunnelAuthStatus | ||
.filter { $0.isInitialized } | ||
.sink { [weak self] tunnelAuthStatus in | ||
tunnelStore.$status | ||
.sink { [weak self] status in | ||
guard let self = self else { return } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is equivalent to the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's correct. Guards are pretty heavily used in Swift and they turn |
||
|
||
Task { | ||
await MainActor.run { | ||
if case .noTunnelFound = tunnelAuthStatus { | ||
if case .invalid = status { | ||
self.needsTunnelPermission = true | ||
} else { | ||
self.needsTunnelPermission = false | ||
|
@@ -66,19 +65,12 @@ public final class AskPermissionViewModel: ObservableObject { | |
} | ||
} | ||
.store(in: &cancellables) | ||
|
||
} | ||
|
||
func grantPermissionButtonTapped() { | ||
Task { | ||
do { | ||
try await self.tunnelStore.createTunnel() | ||
} catch { | ||
#if os(macOS) | ||
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) { | ||
AppStore.WindowDefinition.askPermission.bringAlreadyOpenWindowFront() | ||
} | ||
#endif | ||
try await self.tunnelStore.createManager() | ||
} | ||
} | ||
} | ||
|
@@ -90,7 +82,7 @@ public final class AskPermissionViewModel: ObservableObject { | |
#endif | ||
|
||
#if os(macOS) | ||
func closeAskPermissionWindow() { | ||
public func closeAskPermissionWindow() { | ||
AppStore.WindowDefinition.askPermission.window()?.close() | ||
} | ||
#endif | ||
|
@@ -111,11 +103,10 @@ public struct AskPermissionView: View { | |
Image("LogoText") | ||
.resizable() | ||
.scaledToFit() | ||
.frame(maxWidth: 600) | ||
.frame(maxWidth: 320) | ||
.padding(.horizontal, 10) | ||
Spacer() | ||
if $model.needsTunnelPermission.wrappedValue { | ||
|
||
#if os(macOS) | ||
Text( | ||
"Firezone requires your permission to create VPN tunnels.\nUntil it has that permission, all functionality will be disabled." | ||
|
@@ -180,7 +171,6 @@ public struct AskPermissionView: View { | |
.multilineTextAlignment(.center) | ||
#endif | ||
} else { | ||
|
||
#if os(macOS) | ||
Text( | ||
"You can sign in to Firezone by clicking on the Firezone icon in the macOS menu bar.\nYou may now close this window." | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll leave some redundant questions just to make sure I understand how the Apple Client fits together.
So this part is exposing the Rust functions to Swift, we're declaring these two new functions. This is still on the Rust side, so I assume it would error if the signature is wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah! The macros in here are used to generate the bindings.