You've already forked ios-client
mirror of
https://github.com/netbirdio/ios-client.git
synced 2026-05-22 17:10:12 -07:00
f5b1de0cc7
* fix ui state for airplaine mode * fix slide bar * Keep VPN tunnel alive during network unavailability - Add isNetworkUnavailable flag to NetBirdAdapter to track network state - Modify ConnectionListener to stay in 'connecting' state when network is unavailable instead of transitioning to 'disconnected' - Update PacketTunnelProvider to set network unavailable flag and trigger automatic reconnect when network returns - Fix CustomLottieView to show grey 'Disconnected' state immediately when network is lost, without closing the VPN tunnel - Ensure UI shows correct state after app foreground/background cycle This allows the VPN tunnel to survive temporary network outages (e.g. airplane mode) and automatically reconnect when network returns. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Fix UI state after app foreground/background cycle Show correct connected/disconnected state immediately when app returns from background, without replaying animations. Use extensionStatus (iOS VPN state) as the source of truth for UI state. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * netbird credential * Update MainView.swift * Separate button by state * Add gogoleServiceInfo plist reference * Remove dead code in animation state machine and fix copy-to-clipboard UX - Remove unreachable shouldForceReset block in CustomLottieView (already handled by earlier return) - Guard against copying empty fqdn/ip strings when disconnected - Use consistent .smooth animation for both fqdn and ip copy feedback - Remove unreachable shouldForceReset block in CustomLottieView (already handled by earlier return) - Guard against copying empty fqdn/ip strings when disconnected - Use consistent .smooth animation for both fqdn and ip copy feedback * Tab bar * Update peer view * Add offline state handling and network warning banner - Show "Offline" instead of "Connected" when VPN tunnel is active but device has no internet - Add NetworkWarningBanner with "Network Issues" warning when connected without internet - Remove InternetStatusView (online/offline indicator) from connection screen - Add FirstLaunchView onboarding screen - Remove unused components (CustomBackButton, Extensions, JustifiedText, SolidButton, TransparentGradientButton) - Update AboutView, AdvancedView, ServerView, PeerTabView, RouteTabView, iOSNetworksView styling - Add EmptyTabPlaceholder component * Add AppButton component with liquid glass support for iOS 26+ * Update FirstLaunchView.swift * old version * Update project.pbxproj * Code refactoring * Update project.pbxproj * Update MainViewModel.swift --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
95 lines
2.3 KiB
Swift
95 lines
2.3 KiB
Swift
//
|
|
// AppButton.swift
|
|
// NetBird
|
|
//
|
|
// Reusable button with liquid glass on iOS 26+ and classic fallback on earlier versions.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
struct AppButton: View {
|
|
let title: String
|
|
let style: Style
|
|
let action: () -> Void
|
|
|
|
init(_ title: String, style: Style = .default, action: @escaping () -> Void) {
|
|
self.title = title
|
|
self.style = style
|
|
self.action = action
|
|
}
|
|
|
|
var body: some View {
|
|
Button {
|
|
action()
|
|
} label: {
|
|
ZStack {
|
|
background
|
|
HStack {
|
|
Spacer()
|
|
Text(title)
|
|
.font(style.font)
|
|
.foregroundColor(style.foregroundColor)
|
|
.lineLimit(1)
|
|
Spacer()
|
|
}
|
|
}
|
|
.frame(height: style.height)
|
|
}
|
|
}
|
|
|
|
@ViewBuilder
|
|
private var background: some View {
|
|
if #available(iOS 26.0, tvOS 26.0, *) {
|
|
switch style {
|
|
case .primary:
|
|
Capsule()
|
|
.fill(Color.accentColor.opacity(0.8))
|
|
.glassEffect(.regular)
|
|
case .secondary:
|
|
Capsule()
|
|
.fill(Color.white.opacity(0.5))
|
|
.glassEffect(.regular)
|
|
}
|
|
} else {
|
|
switch style {
|
|
case .primary:
|
|
Capsule()
|
|
.fill(Color.accentColor)
|
|
.overlay(
|
|
Capsule()
|
|
.stroke(Color.orange.opacity(0.8), lineWidth: 2)
|
|
)
|
|
case .secondary:
|
|
Capsule()
|
|
.fill(Color.gray.opacity(0.15))
|
|
.overlay(
|
|
Capsule()
|
|
.stroke(Color.primary.opacity(0.12), lineWidth: 1)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
enum Style {
|
|
case primary
|
|
case secondary
|
|
|
|
static let `default`: Self = .primary
|
|
|
|
var foregroundColor: Color {
|
|
switch self {
|
|
case .primary: return .white
|
|
case .secondary: return .primary
|
|
}
|
|
}
|
|
|
|
var font: Font {
|
|
.body.weight(.medium)
|
|
}
|
|
|
|
var height: CGFloat {
|
|
48
|
|
}
|
|
}
|
|
}
|