Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitfc0f5b0

Browse files
refactor: merge session & settings abstractions (#46)
Unfortunately necessary for#52, as we need the HTTP headers from settings when creating the protocol configuration (which is derived from the session). The class retains all the same invariants as before.
1 parent250017b commitfc0f5b0

17 files changed

+119
-176
lines changed

‎Coder Desktop/Coder Desktop/Coder_DesktopApp.swift

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,14 @@ struct DesktopApp: App {
1111
EmptyView()
1212
}
1313
Window("Sign In", id:Windows.login.rawValue){
14-
LoginForm<SecureSession>()
15-
.environmentObject(appDelegate.session)
16-
.environmentObject(appDelegate.settings)
14+
LoginForm()
15+
.environmentObject(appDelegate.state)
1716
}
1817
.windowResizability(.contentSize)
1918
SwiftUI.Settings{
2019
SettingsView<CoderVPNService>()
2120
.environmentObject(appDelegate.vpn)
22-
.environmentObject(appDelegate.settings)
21+
.environmentObject(appDelegate.state)
2322
}
2423
.windowResizability(.contentSize)
2524
}
@@ -29,28 +28,25 @@ struct DesktopApp: App {
2928
classAppDelegate:NSObject,NSApplicationDelegate{
3029
privatevarmenuBarExtra:FluidMenuBarExtra?
3130
letvpn:CoderVPNService
32-
letsession:SecureSession
33-
letsettings:Settings
31+
letstate:AppState
3432

3533
overrideinit(){
3634
vpn=CoderVPNService()
37-
settings=Settings()
38-
session=SecureSession(onChange: vpn.configureTunnelProviderProtocol)
35+
state=AppState(onChange: vpn.configureTunnelProviderProtocol)
3936
}
4037

4138
func applicationDidFinishLaunching(_:Notification){
4239
menuBarExtra=FluidMenuBarExtra(title:"Coder Desktop", image:"MenuBarIcon"){
43-
VPNMenu<CoderVPNService,SecureSession>().frame(width:256)
40+
VPNMenu<CoderVPNService>().frame(width:256)
4441
.environmentObject(self.vpn)
45-
.environmentObject(self.session)
46-
.environmentObject(self.settings)
42+
.environmentObject(self.state)
4743
}
4844
}
4945

5046
// This function MUST eventually call `NSApp.reply(toApplicationShouldTerminate: true)`
5147
// or return `.terminateNow`
5248
func applicationShouldTerminate(_:NSApplication)->NSApplication.TerminateReply{
53-
if !settings.stopVPNOnQuit{return.terminateNow}
49+
if !state.stopVPNOnQuit{return.terminateNow}
5450
Task{
5551
await vpn.stop()
5652
NSApp.reply(toApplicationShouldTerminate:true)

‎Coder Desktop/Coder Desktop/Preview Content/PreviewSession.swift

Lines changed: 0 additions & 29 deletions
This file was deleted.

‎Coder Desktop/Coder Desktop/State.swift

Lines changed: 43 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,20 @@ import KeychainAccess
44
import NetworkExtension
55
import SwiftUI
66

7-
protocolSession:ObservableObject{
8-
varhasSession:Bool{get}
9-
varbaseAccessURL:URL?{get}
10-
varsessionToken:String?{get}
11-
12-
func store(baseAccessURL:URL, sessionToken:String)
13-
func clear()
14-
func tunnelProviderProtocol()->NETunnelProviderProtocol?
15-
}
16-
17-
classSecureSession:ObservableObject,Session{
7+
classAppState:ObservableObject{
188
letappId=Bundle.main.bundleIdentifier!
199

2010
// Stored in UserDefaults
2111
@Publishedprivate(set)varhasSession:Bool{
2212
didSet{
13+
guard persistentelse{return}
2314
UserDefaults.standard.set(hasSession, forKey:Keys.hasSession)
2415
}
2516
}
2617

2718
@Publishedprivate(set)varbaseAccessURL:URL?{
2819
didSet{
20+
guard persistentelse{return}
2921
UserDefaults.standard.set(baseAccessURL, forKey:Keys.baseAccessURL)
3022
}
3123
}
@@ -37,6 +29,27 @@ class SecureSession: ObservableObject, Session {
3729
}
3830
}
3931

32+
@PublishedvaruseLiteralHeaders:Bool=UserDefaults.standard.bool(forKey:Keys.useLiteralHeaders){
33+
didSet{
34+
guard persistentelse{return}
35+
UserDefaults.standard.set(useLiteralHeaders, forKey:Keys.useLiteralHeaders)
36+
}
37+
}
38+
39+
@PublishedvarliteralHeaders:[LiteralHeader]{
40+
didSet{
41+
guard persistentelse{return}
42+
try?UserDefaults.standard.set(JSONEncoder().encode(literalHeaders), forKey:Keys.literalHeaders)
43+
}
44+
}
45+
46+
@PublishedvarstopVPNOnQuit:Bool=UserDefaults.standard.bool(forKey:Keys.stopVPNOnQuit){
47+
didSet{
48+
guard persistentelse{return}
49+
UserDefaults.standard.set(stopVPNOnQuit, forKey:Keys.stopVPNOnQuit)
50+
}
51+
}
52+
4053
func tunnelProviderProtocol()->NETunnelProviderProtocol?{
4154
if !hasSession{returnnil}
4255
letproto=NETunnelProviderProtocol()
@@ -49,37 +62,50 @@ class SecureSession: ObservableObject, Session {
4962
}
5063

5164
privateletkeychain:Keychain
65+
privateletpersistent:Bool
5266

5367
letonChange:((NETunnelProviderProtocol?)->Void)?
5468

55-
publicinit(onChange:((NETunnelProviderProtocol?)->Void)?=nil){
69+
publicinit(onChange:((NETunnelProviderProtocol?)->Void)?=nil,
70+
persistent:Bool=true)
71+
{
72+
self.persistent= persistent
5673
self.onChange= onChange
5774
keychain=Keychain(service:Bundle.main.bundleIdentifier!)
58-
_hasSession=Published(initialValue:UserDefaults.standard.bool(forKey:Keys.hasSession))
59-
_baseAccessURL=Published(initialValue:UserDefaults.standard.url(forKey:Keys.baseAccessURL))
75+
_hasSession=Published(initialValue: persistent?UserDefaults.standard.bool(forKey:Keys.hasSession):false)
76+
_baseAccessURL=Published(
77+
initialValue: persistent?UserDefaults.standard.url(forKey:Keys.baseAccessURL):nil
78+
)
79+
_literalHeaders=Published(
80+
initialValue: persistent?UserDefaults.standard.data(
81+
forKey:Keys.literalHeaders
82+
).flatMap{try?JSONDecoder().decode([LiteralHeader].self, from: $0)}??[]:[]
83+
)
6084
if hasSession{
6185
_sessionToken=Published(initialValue:keychainGet(for:Keys.sessionToken))
6286
}
6387
}
6488

65-
publicfuncstore(baseAccessURL:URL, sessionToken:String){
89+
publicfunclogin(baseAccessURL:URL, sessionToken:String){
6690
hasSession=true
6791
self.baseAccessURL= baseAccessURL
6892
self.sessionToken= sessionToken
6993
iflet onChange{onChange(tunnelProviderProtocol())}
7094
}
7195

72-
publicfuncclear(){
96+
publicfuncclearSession(){
7397
hasSession=false
7498
sessionToken=nil
7599
iflet onChange{onChange(tunnelProviderProtocol())}
76100
}
77101

78102
privatefunc keychainGet(for key:String)->String?{
79-
try? keychain.getString(key)
103+
guard persistentelse{returnnil}
104+
returntry? keychain.getString(key)
80105
}
81106

82107
privatefunc keychainSet(_ value:String?, for key:String){
108+
guard persistentelse{return}
83109
iflet value{
84110
try? keychain.set(value, key: key)
85111
}else{
@@ -91,31 +117,7 @@ class SecureSession: ObservableObject, Session {
91117
staticlethasSession="hasSession"
92118
staticletbaseAccessURL="baseAccessURL"
93119
staticletsessionToken="sessionToken"
94-
}
95-
}
96-
97-
classSettings:ObservableObject{
98-
privateletstore:UserDefaults
99-
@AppStorage(Keys.useLiteralHeaders)varuseLiteralHeaders=false
100120

101-
@PublishedvarliteralHeaders:[LiteralHeader]{
102-
didSet{
103-
try? store.set(JSONEncoder().encode(literalHeaders), forKey:Keys.literalHeaders)
104-
}
105-
}
106-
107-
@AppStorage(Keys.stopVPNOnQuit)varstopVPNOnQuit=true
108-
109-
init(store:UserDefaults=.standard){
110-
self.store= store
111-
_literalHeaders=Published(
112-
initialValue: store.data(
113-
forKey:Keys.literalHeaders
114-
).flatMap{try?JSONDecoder().decode([LiteralHeader].self, from: $0)}??[]
115-
)
116-
}
117-
118-
enumKeys{
119121
staticletuseLiteralHeaders="UseLiteralHeaders"
120122
staticletliteralHeaders="LiteralHeaders"
121123
staticletstopVPNOnQuit="StopVPNOnQuit"

‎Coder Desktop/Coder Desktop/Views/Agents.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import SwiftUI
22

3-
structAgents<VPN:VPNService, S:Session>:View{
3+
structAgents<VPN:VPNService>:View{
44
@EnvironmentObjectvarvpn:VPN
5-
@EnvironmentObjectvarsession:S
5+
@EnvironmentObjectvarstate:AppState
66
@StateprivatevarviewAll=false
77
privateletdefaultVisibleRows=5
88

@@ -15,7 +15,7 @@ struct Agents<VPN: VPNService, S: Session>: View {
1515
letitems= vpn.menuState.sorted
1616
letvisibleItems= viewAll?items[...]: items.prefix(defaultVisibleRows)
1717
ForEach(visibleItems, id: \.id){ agentin
18-
MenuItemView(item: agent, baseAccessURL:session.baseAccessURL!)
18+
MenuItemView(item: agent, baseAccessURL:state.baseAccessURL!)
1919
.padding(.horizontal,Theme.Size.trayMargin)
2020
}
2121
if items.count==0{

‎Coder Desktop/Coder Desktop/Views/AuthButton.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
import SwiftUI
22

3-
structAuthButton<VPN:VPNService, S:Session>:View{
4-
@EnvironmentObjectvarsession:S
3+
structAuthButton<VPN:VPNService>:View{
4+
@EnvironmentObjectvarstate:AppState
55
@EnvironmentObjectvarvpn:VPN
66
@Environment(\.openWindow)varopenWindow
77

88
varbody:someView{
99
Button{
10-
ifsession.hasSession{
10+
ifstate.hasSession{
1111
Task{
1212
await vpn.stop()
13-
session.clear()
13+
state.clearSession()
1414
}
1515
}else{
1616
openWindow(id:.login)
1717
}
1818
} label:{
1919
ButtonRowView{
20-
Text(session.hasSession?"Sign out":"Sign in")
20+
Text(state.hasSession?"Sign out":"Sign in")
2121
}
2222
}.buttonStyle(.plain)
2323
}

‎Coder Desktop/Coder Desktop/Views/LoginForm.swift

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import CoderSDK
22
import SwiftUI
33

4-
structLoginForm<S:Session>:View{
5-
@EnvironmentObjectvarsession:S
6-
@EnvironmentObjectvarsettings:Settings
4+
structLoginForm:View{
5+
@EnvironmentObjectvarstate:AppState
76
@Environment(\.dismiss)privatevardismiss
87

98
@StateprivatevarbaseAccessURL:String=""
@@ -38,7 +37,7 @@ struct LoginForm<S: Session>: View {
3837
}
3938
.animation(.easeInOut, value: currentPage)
4039
.onAppear{
41-
baseAccessURL=session.baseAccessURL?.absoluteString?? baseAccessURL
40+
baseAccessURL=state.baseAccessURL?.absoluteString?? baseAccessURL
4241
sessionToken=""
4342
}
4443
.alert("Error", isPresented:Binding(
@@ -72,14 +71,14 @@ struct LoginForm<S: Session>: View {
7271
}
7372
loading=true
7473
defer{ loading=false}
75-
letclient=Client(url: url, token: sessionToken, headers:settings.literalHeaders.map{ $0.toSDKHeader()})
74+
letclient=Client(url: url, token: sessionToken, headers:state.literalHeaders.map{ $0.toSDKHeader()})
7675
do{
7776
_=tryawait client.user("me")
7877
}catch{
7978
loginError=.failedAuth(error)
8079
return
8180
}
82-
session.store(baseAccessURL: url, sessionToken: sessionToken)
81+
state.login(baseAccessURL: url, sessionToken: sessionToken)
8382
dismiss()
8483
}
8584

@@ -219,7 +218,7 @@ enum LoginField: Hashable {
219218

220219
#if DEBUG
221220
#Preview{
222-
LoginForm<PreviewSession>()
223-
.environmentObject(PreviewSession())
221+
LoginForm()
222+
.environmentObject(AppState())
224223
}
225224
#endif

‎Coder Desktop/Coder Desktop/Views/Settings/GeneralTab.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ import LaunchAtLogin
22
import SwiftUI
33

44
structGeneralTab:View{
5-
@EnvironmentObjectvarsettings:Settings
5+
@EnvironmentObjectvarstate:AppState
66
varbody:someView{
77
Form{
88
Section{
99
LaunchAtLogin.Toggle("Launch at Login")
1010
}
1111
Section{
12-
Toggle(isOn: $settings.stopVPNOnQuit){
12+
Toggle(isOn: $state.stopVPNOnQuit){
1313
Text("Stop VPN on Quit")
1414
}
1515
}

‎Coder Desktop/Coder Desktop/Views/Settings/LiteralHeaderModal.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import SwiftUI
33
structLiteralHeaderModal:View{
44
varexistingHeader:LiteralHeader?
55

6-
@EnvironmentObjectvarsettings:Settings
6+
@EnvironmentObjectvarstate:AppState
77
@Environment(\.dismiss)privatevardismiss
88

99
@Stateprivatevarheader:String=""
@@ -35,11 +35,11 @@ struct LiteralHeaderModal: View {
3535
func submit(){
3636
defer{dismiss()}
3737
iflet existingHeader{
38-
settings.literalHeaders.removeAll{ $0== existingHeader}
38+
state.literalHeaders.removeAll{ $0== existingHeader}
3939
}
4040
letnewHeader=LiteralHeader(header: header, value: value)
41-
if !settings.literalHeaders.contains(newHeader){
42-
settings.literalHeaders.append(newHeader)
41+
if !state.literalHeaders.contains(newHeader){
42+
state.literalHeaders.append(newHeader)
4343
}
4444
}
4545
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp