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

Commitdc8972e

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

File tree

17 files changed

+472
-64
lines changed

17 files changed

+472
-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: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import FluidMenuBarExtra
2+
import SwiftData
23
import SwiftUI
34

45
@main
@@ -14,6 +15,11 @@ struct DesktopApp: App {
1415
LoginForm<PreviewSession>().environmentObject(appDelegate.session)
1516
}
1617
.windowResizability(.contentSize)
18+
SwiftUI.Settings{SettingsView<PreviewVPN>()
19+
.environmentObject(appDelegate.vpn)
20+
.environmentObject(appDelegate.settings)
21+
}
22+
.windowResizability(.contentSize)
1723
}
1824
}
1925

@@ -22,10 +28,12 @@ class AppDelegate: NSObject, NSApplicationDelegate {
2228
privatevarmenuBarExtra:FluidMenuBarExtra?
2329
letvpn:PreviewVPN
2430
letsession:PreviewSession
31+
letsettings:Settings
2532

2633
overrideinit(){
27-
// TODO: Replace with realimplementations
34+
// TODO: Replace with realimplementation
2835
vpn=PreviewVPN()
36+
settings=Settings()
2937
session=PreviewSession()
3038
}
3139

@@ -34,10 +42,24 @@ class AppDelegate: NSObject, NSApplicationDelegate {
3442
VPNMenu<PreviewVPN,PreviewSession>().frame(width:256)
3543
.environmentObject(self.vpn)
3644
.environmentObject(self.session)
45+
.environmentObject(self.settings)
3746
}
3847
}
3948

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

‎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: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import CoderSDK
2+
import SwiftData
23
import SwiftUI
34

45
structLoginForm<S:Session>:View{
56
@EnvironmentObjectvarsession:S
7+
@EnvironmentObjectvarsettings:Settings
68
@Environment(\.dismiss)privatevardismiss
79

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