Files
ios-client/NetBird/Source/App/Views/RouteTabView.swift
T
evgeniyChepelev f5b1de0cc7 Redesign app (#60)
* 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>
2026-03-02 15:23:51 +01:00

89 lines
2.9 KiB
Swift

//
// RouteTabView.swift
// NetBird
//
// Created by Pascal Fischer on 06.05.24.
//
// Shared between iOS and tvOS.
// Uses Screen helper for platform-independent sizing.
//
import SwiftUI
struct RouteTabView: View {
@EnvironmentObject var viewModel: ViewModel
var body: some View {
ZStack {
Color("BgMenu")
VStack {
Spacer(minLength: 0)
if viewModel.vpnDisplayState == .connected && viewModel.routeViewModel.routeInfo.count > 0 {
VStack {
RouteSelectionHeader(routeViewModel: viewModel.routeViewModel)
RouteListView(viewModel: viewModel, routeViewModel: viewModel.routeViewModel, peerViewModel: viewModel.peerViewModel)
}
} else {
NoRoutesView()
}
Spacer(minLength: 0)
}
}
.onAppear {
self.viewModel.routeViewModel.getRoutes()
}
}
}
struct RouteSelectionHeader: View {
@ObservedObject var routeViewModel: RoutesViewModel
var body: some View {
HStack {
CustomTextField(placeholder: "search resources", text: self.$routeViewModel.routeFilter, secure: .constant(false))
.padding([.top, .bottom], 10)
Menu {
Button(action: { self.routeViewModel.selectionFilter = "All" }) {
Text("All")
}
Button(action: { self.routeViewModel.selectionFilter = "Enabled" }) {
Text("Enabled")
}
Button(action: { self.routeViewModel.selectionFilter = "Disabled" }) {
Text("Disabled")
}
} label: {
Image("icon-filter")
.padding([.leading, .trailing], 4)
}
}.padding([.leading, .trailing])
}
}
struct RouteListView: View {
@ObservedObject var viewModel: ViewModel
@ObservedObject var routeViewModel: RoutesViewModel
@ObservedObject var peerViewModel: PeerViewModel
var body: some View {
ScrollView {
ForEach(Array(self.routeViewModel.filteredRoutes.enumerated()), id: \.element.id) { index, route in
RouteCard(route: route, selectedRouteId: $routeViewModel.selectedRouteId, orientationTop: index > 3, peerViewModel: peerViewModel, routeViewModel: routeViewModel)
.zIndex(routeViewModel.selectedRouteId == route.id ? 1 : 0)
.opacity(self.routeViewModel.tappedRoute == route ? 0.3 : 1.0)
}
}
}
}
struct NoRoutesView: View {
var body: some View {
EmptyTabPlaceholder(
message: "It looks like there are no resources that you can connect to...",
learnMoreURL: URL(string: "https://docs.netbird.io/how-to/networks")
)
}
}