ReadKeep/readeck/UI/readeckApp.swift
Ilyas Hallak e4657aa281 Fix offline reading bugs and improve network monitoring (Phase 5)
Bugfixes:
- Add toggle for offline mode simulation (DEBUG only)
- Fix VPN false-positives with interface count check
- Add detailed error logging for download failures
- Fix last sync timestamp display
- Translate all strings to English

Network Monitoring:
- Add NetworkMonitorRepository with NWPathMonitor
- Check path.status AND availableInterfaces for reliability
- Add manual reportConnectionFailure/Success methods
- Auto-load cached bookmarks when offline
- Visual debug banner (green=online, red=offline)

Architecture:
- Clean architecture with Repository → UseCase → ViewModel
- Network status in AppSettings for global access
- Combine publishers for reactive updates
2025-11-21 21:37:24 +01:00

117 lines
3.4 KiB
Swift

//
// readeckApp.swift
// readeck
//
// Created by Ilyas Hallak on 10.06.25.
//
import SwiftUI
import netfox
@main
struct readeckApp: App {
@State private var appViewModel = AppViewModel()
@StateObject private var appSettings = AppSettings()
@Environment(\.scenePhase) private var scenePhase
var body: some Scene {
WindowGroup {
Group {
if appViewModel.hasFinishedSetup {
MainTabView()
} else {
OnboardingServerView()
.padding()
}
}
.environmentObject(appSettings)
.environment(\.managedObjectContext, CoreDataManager.shared.context)
.preferredColorScheme(appSettings.theme.colorScheme)
.onAppear {
#if DEBUG
NFX.sharedInstance().start()
#endif
Task {
await loadAppSettings()
}
appViewModel.bindNetworkStatus(to: appSettings)
}
.onReceive(NotificationCenter.default.publisher(for: .settingsChanged)) { _ in
Task {
await loadAppSettings()
}
}
.onChange(of: scenePhase) { oldPhase, newPhase in
if newPhase == .active {
Task {
await appViewModel.onAppResume()
}
}
}
}
}
private func loadAppSettings() async {
let settingsRepository = SettingsRepository()
let settings = try? await settingsRepository.loadSettings()
await MainActor.run {
appSettings.settings = settings
}
}
}
struct TestView: View {
var body: some View {
if #available(iOS 26.0, *) {
Text("hello")
.toolbar {
ToolbarSpacer(.flexible)
ToolbarItem {
Button {
} label: {
Label("Favorite", systemImage: "share")
.symbolVariant(.none)
}
}
ToolbarSpacer(.fixed)
ToolbarItemGroup {
Button {
} label: {
Label("Favorite", systemImage: "heart")
.symbolVariant(.none)
}
Button("Info", systemImage: "info") {
}
}
ToolbarItemGroup(placement: .bottomBar) {
Spacer()
Button {
} label: {
Label("Favorite", systemImage: "heart")
.symbolVariant(.none)
}
Button("Info", systemImage: "info") {
}
}
}
.toolbar(removing: .title)
.ignoresSafeArea(edges: .top)
} else {
Text("hello1")
}
}
}