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

Commit85e0300

Browse files
committed
feat: support user-supplied literal headers
1 parent5d97953 commit85e0300

File tree

17 files changed

+467
-64
lines changed

17 files changed

+467
-64
lines changed

‎Coder Desktop/Coder Desktop.xcodeproj/project.pbxproj

Lines changed: 139 additions & 35 deletions
Large diffs are not rendered by default.

‎Coder Desktop/Coder Desktop.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 21 additions & 3 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Coder Desktop/Coder Desktop/About.swift

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,7 @@ enum About {
3232

3333
@MainActor
3434
staticfunc open(){
35-
#if compiler(>=5.9) && canImport(AppKit)
36-
if #available(macOS14,*){
37-
NSApp.activate()
38-
}else{
39-
NSApp.activate(ignoringOtherApps:true)
40-
}
41-
#else
42-
NSApp.activate(ignoringOtherApps:true)
43-
#endif
35+
appActivate()
4436
NSApp.orderFrontStandardAboutPanel(options:[
4537
.credits: credits,
4638
])

‎Coder Desktop/Coder Desktop/Coder_DesktopApp.swift

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ struct DesktopApp: App {
1414
LoginForm<PreviewSession>().environmentObject(appDelegate.session)
1515
}
1616
.windowResizability(.contentSize)
17+
SwiftUI.Settings{SettingsView<PreviewVPN>()
18+
.environmentObject(appDelegate.vpn)
19+
.environmentObject(appDelegate.settings)
20+
}
21+
.windowResizability(.contentSize)
1722
}
1823
}
1924

@@ -22,10 +27,12 @@ class AppDelegate: NSObject, NSApplicationDelegate {
2227
privatevarmenuBarExtra:FluidMenuBarExtra?
2328
letvpn:PreviewVPN
2429
letsession:PreviewSession
30+
letsettings:Settings
2531

2632
overrideinit(){
27-
// TODO: Replace with realimplementations
33+
// TODO: Replace with realimplementation
2834
vpn=PreviewVPN()
35+
settings=Settings()
2936
session=PreviewSession()
3037
}
3138

@@ -34,10 +41,24 @@ class AppDelegate: NSObject, NSApplicationDelegate {
3441
VPNMenu<PreviewVPN,PreviewSession>().frame(width:256)
3542
.environmentObject(self.vpn)
3643
.environmentObject(self.session)
44+
.environmentObject(self.settings)
3745
}
3846
}
3947

4048
func applicationShouldTerminateAfterLastWindowClosed(_:NSApplication)->Bool{
4149
false
4250
}
4351
}
52+
53+
@MainActor
54+
func appActivate(){
55+
#if compiler(>=5.9) && canImport(AppKit)
56+
if #available(macOS14,*){
57+
NSApp.activate()
58+
}else{
59+
NSApp.activate(ignoringOtherApps:true)
60+
}
61+
#else
62+
NSApp.activate(ignoringOtherApps:true)
63+
#endif
64+
}

‎Coder Desktop/Coder Desktop/Session.swiftrenamed to‎Coder Desktop/Coder Desktop/State.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import CoderSDK
12
import Foundation
23
import KeychainAccess
34
import NetworkExtension
5+
import SwiftUI
46

57
protocolSession:ObservableObject{
68
varhasSession:Bool{get}
@@ -89,3 +91,47 @@ class SecureSession: ObservableObject, Session {
8991
staticletsessionToken="sessionToken"
9092
}
9193
}
94+
95+
classSettings:ObservableObject{
96+
letstore:UserDefaults
97+
@AppStorage(Keys.useLiteralHeaders)varuseLiteralHeaders=false
98+
99+
@PublishedvarliteralHeaders:[LiteralHeader]{
100+
didSet{
101+
try? store.set(JSONEncoder().encode(literalHeaders), forKey:Keys.literalHeaders)
102+
}
103+
}
104+
105+
init(store:UserDefaults=UserDefaults.standard){
106+
self.store= store
107+
_literalHeaders=Published(
108+
initialValue:UserDefaults.standard.data(
109+
forKey:Keys.literalHeaders
110+
).flatMap{try?JSONDecoder().decode([LiteralHeader].self, from: $0)}??[]
111+
)
112+
}
113+
114+
enumKeys{
115+
staticletuseLiteralHeaders="UseLiteralHeaders"
116+
staticletliteralHeaders="LiteralHeaders"
117+
}
118+
}
119+
120+
structLiteralHeader:Hashable,Identifiable,Equatable,Codable{
121+
varheader:String
122+
varvalue:String
123+
varid:String{
124+
"\(header):\(value)"
125+
}
126+
127+
init(header:String, value:String){
128+
self.header= header
129+
self.value= value
130+
}
131+
}
132+
133+
extensionLiteralHeader{
134+
func toSDKHeader()->HTTPHeader{
135+
return.init(header: header, value: value)
136+
}
137+
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import SwiftUI
33

44
structLoginForm<S:Session>:View{
55
@EnvironmentObjectvarsession:S
6+
@EnvironmentObjectvarsettings:Settings
67
@Environment(\.dismiss)privatevardismiss
78

89
@StateprivatevarbaseAccessURL:String=""
@@ -68,7 +69,7 @@ struct LoginForm<S: Session>: View {
6869
}
6970
loading=true
7071
defer{ loading=false}
71-
letclient=Client(url: url, token: sessionToken)
72+
letclient=Client(url: url, token: sessionToken, headers: settings.literalHeaders.map{ $0.toSDKHeader()})
7273
do{
7374
_=tryawait client.user("me")
7475
}catch{
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import LaunchAtLogin
2+
import SwiftUI
3+
4+
structGeneralTab:View{
5+
varbody:someView{
6+
Form{
7+
Section{
8+
LaunchAtLogin.Toggle("Launch at Login")
9+
}
10+
}.formStyle(.grouped)
11+
}
12+
}
13+
14+
#Preview{
15+
GeneralTab()
16+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import SwiftUI
2+
3+
structLiteralHeaderModal:View{
4+
varexistingHeader:LiteralHeader?
5+
6+
@EnvironmentObjectvarsettings:Settings
7+
@Environment(\.dismiss)privatevardismiss
8+
9+
@Stateprivatevarheader:String=""
10+
@Stateprivatevarvalue:String=""
11+
12+
varbody:someView{
13+
VStack(spacing:0){
14+
Form{
15+
Section{
16+
TextField("Header", text: $header)
17+
TextField("Value", text: $value)
18+
}
19+
}.formStyle(.grouped).scrollDisabled(true).padding(.horizontal)
20+
Divider()
21+
HStack{
22+
Spacer()
23+
Button("Cancel", action:{dismiss()}).keyboardShortcut(.cancelAction)
24+
Button(existingHeader==nil?"Add":"Save", action: submit)
25+
.keyboardShortcut(.defaultAction)
26+
}.padding(20)
27+
}.onAppear{
28+
iflet existingHeader{
29+
self.header= existingHeader.header
30+
self.value= existingHeader.value
31+
}
32+
}
33+
}
34+
35+
func submit(){
36+
defer{dismiss()}
37+
iflet existingHeader{
38+
settings.literalHeaders.removeAll{ $0== existingHeader}
39+
}
40+
letnewHeader=LiteralHeader(header: header, value: value)
41+
if !settings.literalHeaders.contains(newHeader){
42+
settings.literalHeaders.append(newHeader)
43+
}
44+
}
45+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import SwiftUI
2+
3+
structLiteralHeadersSection<VPN:VPNService>:View{
4+
@EnvironmentObjectvarvpn:VPN
5+
@EnvironmentObjectvarsettings:Settings
6+
7+
@StateprivatevarselectedHeader:LiteralHeader.ID?
8+
@StateprivatevareditingHeader:LiteralHeader?
9+
@StateprivatevaraddingNewHeader=false
10+
11+
letinspection=Inspection<Self>()
12+
13+
varbody:someView{
14+
Section{
15+
Toggle(isOn: settings.$useLiteralHeaders){
16+
Text("HTTP Headers")
17+
Text("When enabled, these headers will be included on all outgoing HTTP requests.")
18+
if vpn.state!=.disabled{Text("Cannot be modified while Coder VPN is enabled.")}
19+
}
20+
.controlSize(.large)
21+
22+
Table(settings.literalHeaders, selection: $selectedHeader){
23+
TableColumn("Header", value: \.header)
24+
TableColumn("Value", value: \.value)
25+
}.opacity(settings.useLiteralHeaders?1:0.5)
26+
.frame(minWidth:400, minHeight:200)
27+
.padding(.bottom,25)
28+
.overlay(alignment:.bottom){
29+
VStack(alignment:.leading, spacing:0){
30+
Divider()
31+
HStack(spacing:0){
32+
Button{
33+
addingNewHeader=true
34+
} label:{
35+
Image(systemName:"plus")
36+
.frame(width:24, height:24)
37+
}
38+
Divider()
39+
Button{
40+
settings.literalHeaders.removeAll{ $0.id== selectedHeader}
41+
selectedHeader=nil
42+
} label:{
43+
Image(systemName:"minus")
44+
.frame(width:24, height:24)
45+
}.disabled(selectedHeader==nil)
46+
}
47+
.buttonStyle(.borderless)
48+
}
49+
.background(.primary.opacity(0.04))
50+
.fixedSize(horizontal:false, vertical:true)
51+
}
52+
.background(.primary.opacity(0.04))
53+
.contextMenu(forSelectionType:LiteralHeader.ID.self, menu:{ _in},
54+
primaryAction:{ selectedHeadersin
55+
iflet firstHeader= selectedHeaders.first{
56+
editingHeader= settings.literalHeaders.first(where:{ $0.id== firstHeader})
57+
}
58+
})
59+
.disabled(!settings.useLiteralHeaders)
60+
}
61+
.sheet(isPresented: $addingNewHeader){
62+
LiteralHeaderModal()
63+
}
64+
.sheet(item: $editingHeader){ headerin
65+
LiteralHeaderModal(existingHeader: header)
66+
}.onTapGesture{
67+
selectedHeader=nil
68+
}.disabled(vpn.state!=.disabled)
69+
.onReceive(inspection.notice){self.inspection.visit(self, $0)} // ViewInspector
70+
}
71+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import SwiftUI
2+
3+
structNetworkTab<VPN:VPNService>:View{
4+
varbody:someView{
5+
Form{
6+
LiteralHeadersSection<VPN>()
7+
}
8+
.formStyle(.grouped)
9+
}
10+
}
11+
12+
#Preview{
13+
NetworkTab<PreviewVPN>()
14+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import SwiftUI
2+
3+
structSettingsView<VPN:VPNService>:View{
4+
@AppStorage("SettingsSelectedIndex")privatevarselection:SettingsTab=.general
5+
6+
varbody:someView{
7+
TabView(selection: $selection){
8+
GeneralTab()
9+
.tabItem{
10+
Label("General", systemImage:"gearshape")
11+
}.tag(SettingsTab.general)
12+
NetworkTab<VPN>()
13+
.tabItem{
14+
Label("Network", systemImage:"dot.radiowaves.left.and.right")
15+
}.tag(SettingsTab.network)
16+
}.frame(width:600)
17+
.frame(maxHeight:500)
18+
.scrollContentBackground(.hidden)
19+
.fixedSize()
20+
}
21+
}
22+
23+
enumSettingsTab:Int{
24+
case general
25+
case network
26+
}

‎Coder Desktop/Coder Desktop/Views/Util.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Combine
2+
import SwiftUI
23

34
// This is required for inspecting stateful views
45
finalclassInspection<V>{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp