Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save swift2geek/4efdf2fba26afa28505fa6d41b271ce2 to your computer and use it in GitHub Desktop.
Save swift2geek/4efdf2fba26afa28505fa6d41b271ce2 to your computer and use it in GitHub Desktop.
//
// RootView.swift
// nutritionApp
//
//
//
import Combine
import Factory
import SwiftUI
import ToastUI
struct RootView: View {
@ObservedObject var navigationService: NavigationService
@ObservedObject var appViewBuilder: ApplicationViewBuilder
@State private var selectedTab: Int = 0
@State private var cancellables = Set<AnyCancellable>()
private let userService: UserServiceType = Container.shared.userService()
@State private var isLoading = false
@State private var showToast = false
@State private var toastMessage = ""
var authService: any AuthServiceType = Container.shared.authService()
var body: some View {
ZStack {
if navigationService.isOnboardingCompleted {
mainTabView
.onAppear(perform: {
// TODO: - @vv ВЫНЕСТИ ЛОГИКУ в Интерактор
if let authToken = authService.getToken() {
isLoading = true
authService.validateToken(token: authToken)
.sink(receiveCompletion: { completion in
isLoading = false
switch completion {
case .finished:
print("Token validation completed.")
case .failure(let error):
print("Token validation failed: \(error.localizedDescription)")
toastMessage = "Token validation failed: \(error.localizedDescription)"
showToast = true
// TODO: - logout user! Rethink how it should be done centralized
navigationService.isOnboardingCompleted = false
}
}, receiveValue: { userDTO in
print("Received user: \(userDTO)")
let user = User(from: userDTO)
self.userService.save(user)
})
.store(in: &cancellables)
}
})
} else {
onboardingStack
}
if isLoading {
ProgressView("Loading...")
.progressViewStyle(CircularProgressViewStyle())
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.black.opacity(0.5))
}
}
.toast(isPresented: $showToast, dismissAfter: 2.0) {
ToastView(toastMessage)
.toastViewStyle(WarningToastViewStyle())
}
}
var mainTabView: some View {
TabView(selection: $selectedTab) {
appViewBuilder.build(view: .feed)
.tabItem {
Image("chat")
}
.tag(0)
appViewBuilder.build(view: .statistics)
.tabItem {
Image("shift")
}
.tag(1)
NavigationStack(path: Binding(get: {
navigationService.items.filter { isProfileRelatedPath($0) }
}, set: { filteredPaths in
navigationService.items = filteredPaths
})) {
appViewBuilder.build(view: .profile)
.navigationDestination(for: Views.self) { path in
appViewBuilder.build(view: path)
}
}
.tabItem {
Image("user")
}
.tag(2)
.fullScreenCover(isPresented: .constant($navigationService.modalView.wrappedValue != nil)) {
if let modal = navigationService.modalView {
appViewBuilder.build(view: modal)
}
}
appViewBuilder.build(view: .settings)
.tabItem {
Image("settings")
}
.tag(3)
}
.accentColor(.main)
}
var onboardingStack: some View {
NavigationStack(path: $navigationService.items) {
appViewBuilder.build(view: .main)
.navigationDestination(for: Views.self) { path in
appViewBuilder.build(view: path)
}
}
.fullScreenCover(isPresented: .constant($navigationService.modalView.wrappedValue != nil)) {
if let modal = navigationService.modalView {
appViewBuilder.build(view: modal)
}
}
.alert(isPresented: .constant($navigationService.alert.wrappedValue != nil)) {
switch navigationService.alert {
case .defaultAlert(let yesAction, let noAction):
return Alert(title: Text("Title"),
primaryButton: .default(Text("Yes"), action: yesAction),
secondaryButton: .destructive(Text("No"), action: noAction))
case .none:
fatalError("Alert data not found.")
}
}
}
// TODO: - @VV crutch to filter out unexpected views in the second naviStack in Profile tab
private func isProfileRelatedPath(_ path: Views) -> Bool {
switch path {
case .profile, .editWeight, .editHeight, .editWeightTarget, .accountPage:
return true
default:
return false
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment