Files
ios-client/NetBird/Source/App/Views/iOS/iOSSettingsView.swift
T
evgeniyChepelev 0327624b30 Multi-profiles (#80)
* fix layout on ipad

* Create multi profiles

* multi-profile server config, connection cache, and auth fixes

 Split ProfilesView into ProfilesListView, AddProfileSheet, ProfileBadge, AddProfileViewModel
- Add server URL + setup key fields to Add Profile screen
- Store per-profile connection data (ip/fqdn/managementURL) as typed model in ProfileConnectionCache
- Show cached connection info immediately on profile switch; empty if no prior data
- Fix profile deletion persistence via tombstone in profiles.json
- Fix logout to remove both netbird.cfg and state.json (cfg holds auth tokens)
- Preserve managementURL in UI after logout via cache fallback
- Guard polling from overwriting new profile's data during disconnect/reconnect cycle

* fix(multi-profile): reinitialize VPN adapter on profile switch and show current server URL

* Update project.pbxproj

* fix(multi-profile): prevent default server overwrite on logout/re-login

* Update PacketTunnelProvider.swift

* fix(multi-profile): address code review findings

- Normalize only scheme and host to lowercase when saving management
  server URL; previously the full URL was lowercased which could corrupt
  case-sensitive paths on self-hosted servers
- Move switchConnectionInfo(to:) inside the do-block so the connection
  UI is only updated after a successful profile switch
- Add ProfileConnectionCache.remove(for:) and clearConnectionData(for:)
  to prevent stale ip/fqdn/managementURL from persisting after a profile
  is deleted or logged out; call them from removeProfile and logoutProfile
- Use ASWebAuthenticationSession.Callback.customScheme on iOS 17.4+,
  falling back to the deprecated callbackURLScheme initializer on older
  versions; add a comment explaining why "http" is used and that a
  proper fix requires custom-scheme support in the SDK
- Guard presentationAnchor against a missing key window with
  assertionFailure in debug builds instead of silently returning an
  empty UIWindow
2026-04-22 10:06:51 +02:00

126 lines
4.5 KiB
Swift

//
// iOSSettingsView.swift
// NetBird
//
// Settings tab: Advanced, About, Change Server, Documentation.
//
import SwiftUI
#if os(iOS)
struct iOSSettingsView: View {
@EnvironmentObject var viewModel: ViewModel
var body: some View {
List {
Section {
NavigationLink {
ProfilesListView()
} label: {
HStack {
Image(systemName: "person.2.fill")
.foregroundColor(.accentColor)
.frame(width: 24)
Text("Profiles")
.foregroundColor(Color("TextPrimary"))
Spacer()
Text(viewModel.activeProfileName)
.foregroundColor(Color("TextSecondary"))
.font(.system(size: 14))
}
}
}
Section(header: Text("Connection")) {
Button {
viewModel.showChangeServerAlert = true
} label: {
HStack {
Image(systemName: "server.rack")
.foregroundColor(.accentColor)
.frame(width: 24)
Text("Change Server")
.foregroundColor(Color("TextPrimary"))
}
}
}
Section(header: Text("Settings")) {
NavigationLink {
VPNOnDemandView()
} label: {
HStack {
Image(systemName: "arrow.trianglehead.2.clockwise")
.foregroundColor(.accentColor)
.frame(width: 24)
Text("VPN On Demand")
.foregroundColor(Color("TextPrimary"))
}
}
NavigationLink {
AdvancedView()
} label: {
HStack {
Image(systemName: "gearshape.2")
.foregroundColor(.accentColor)
.frame(width: 24)
Text("Advanced")
.foregroundColor(Color("TextPrimary"))
}
}
}
Section(header: Text("Information")) {
NavigationLink {
AboutView()
} label: {
HStack {
Image(systemName: "info.circle")
.foregroundColor(.accentColor)
.frame(width: 24)
Text("About")
.foregroundColor(Color("TextPrimary"))
}
}
if let docsURL = URL(string: "https://docs.netbird.io") {
Link(destination: docsURL) {
HStack {
Image(systemName: "book")
.foregroundColor(.accentColor)
.frame(width: 24)
Text("Documentation")
.foregroundColor(Color("TextPrimary"))
Spacer()
Image(systemName: "arrow.up.right.square")
.foregroundColor(Color("TextSecondary"))
.font(.system(size: 14))
}
}
}
}
Section {
HStack {
Spacer()
Text("Version \(appVersion)")
.font(.system(size: 14))
.foregroundColor(Color("TextSecondary"))
Spacer()
}
}
}
.listStyle(InsetGroupedListStyle())
.navigationTitle("Settings")
.navigationBarTitleDisplayMode(.inline)
}
private var appVersion: String {
Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "unknown"
}
}
#endif