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

Commitfdb8545

Browse files
feat: support user-supplied literal headers (#24)
1 parent63f29ef commitfdb8545

File tree

17 files changed

+434
-64
lines changed

17 files changed

+434
-64
lines changed

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

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

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

Lines changed: 12 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: 14 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,6 +41,7 @@ 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

@@ -49,3 +57,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
4957
false
5058
}
5159
}
60+
61+
@MainActor
62+
func appActivate(){
63+
NSApp.activate()
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+
privateletstore: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=.standard){
106+
self.store= store
107+
_literalHeaders=Published(
108+
initialValue: store.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>{

‎Coder Desktop/Coder Desktop/Views/VPNMenu.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import SwiftUI
33
structVPNMenu<VPN:VPNService, S:Session>:View{
44
@EnvironmentObjectvarvpn:VPN
55
@EnvironmentObjectvarsession:S
6+
@Environment(\.openSettings)privatevaropenSettings
67

78
letinspection=Inspection<Self>()
89

@@ -21,6 +22,8 @@ struct VPNMenu<VPN: VPNService, S: Session>: View {
2122
)){
2223
Text("CoderVPN")
2324
.frame(maxWidth:.infinity, alignment:.leading)
25+
.font(.body.bold())
26+
.foregroundColor(.primary)
2427
}.toggleStyle(.switch)
2528
.disabled(vpnDisabled)
2629
}
@@ -50,6 +53,12 @@ struct VPNMenu<VPN: VPNService, S: Session>: View {
5053
TrayDivider()
5154
}
5255
AuthButton<VPN,S>()
56+
Button{
57+
openSettings()
58+
appActivate()
59+
} label:{
60+
ButtonRowView{Text("Settings")}
61+
}.buttonStyle(.plain)
5362
Button{
5463
About.open()
5564
} label:{

‎Coder Desktop/Coder Desktop/Windows.swift

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,7 @@ enum Windows: String {
88
extensionOpenWindowAction{
99
// Type-safe wrapper for opening windows that also focuses the new window
1010
func callAsFunction(id:Windows){
11-
#if compiler(>=5.9) && canImport(AppKit)
12-
if #available(macOS14,*){
13-
NSApp.activate()
14-
}else{
15-
NSApp.activate(ignoringOtherApps:true)
16-
}
17-
#else
18-
NSApp.activate(ignoringOtherApps:true)
19-
#endif
11+
appActivate()
2012
callAsFunction(id: id.rawValue)
2113
// The arranging behaviour is flakey without this
2214
NSApp.arrangeInFront(nil)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp