From 695459ac06b9f8dda82db061985ff6c46c49c12c Mon Sep 17 00:00:00 2001 From: Trey t Date: Tue, 20 Jun 2023 20:49:32 -0500 Subject: [PATCH] WIP --- Werkout_ios.xcodeproj/project.pbxproj | 4 + Werkout_ios/APIModels/Exercise.swift | 4 +- Werkout_ios/APIModels/Workout.swift | 4 +- Werkout_ios/BridgeModule.swift | 2 +- Werkout_ios/Extensions.swift | 31 +++++ Werkout_ios/Network/Fetchables.swift | 11 ++ Werkout_ios/Network/Network.swift | 57 +++++++- Werkout_ios/Views/AddExerciseView.swift | 9 +- Werkout_ios/Views/AllWorkoutsView.swift | 40 +++--- .../CreateWorkoutViews/CreateViewModels.swift | 25 ++++ .../CreateWorkoutMainView.swift | 2 +- .../Views/ExternalWorkoutDetailView.swift | 131 ++++++++++-------- Werkout_ios/Views/MainView.swift | 2 +- Werkout_ios/Views/WorkoutDetailView.swift | 57 +++++--- Werkout_ios/Werkout_iosApp.swift | 19 ++- 15 files changed, 287 insertions(+), 111 deletions(-) create mode 100644 Werkout_ios/Extensions.swift diff --git a/Werkout_ios.xcodeproj/project.pbxproj b/Werkout_ios.xcodeproj/project.pbxproj index 0757082..03c4f45 100644 --- a/Werkout_ios.xcodeproj/project.pbxproj +++ b/Werkout_ios.xcodeproj/project.pbxproj @@ -39,6 +39,7 @@ 1CF65A7D2A41275D0042FFBD /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CF65A7C2A41275D0042FFBD /* Network.swift */; }; 1CF65A7F2A4129320042FFBD /* Fetchables.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CF65A7E2A4129320042FFBD /* Fetchables.swift */; }; 1CF65A812A412AA30042FFBD /* DataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CF65A802A412AA30042FFBD /* DataStore.swift */; }; + 1CF65A832A42347D0042FFBD /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CF65A822A42347D0042FFBD /* Extensions.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -77,6 +78,7 @@ 1CF65A7C2A41275D0042FFBD /* Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = ""; }; 1CF65A7E2A4129320042FFBD /* Fetchables.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fetchables.swift; sourceTree = ""; }; 1CF65A802A412AA30042FFBD /* DataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStore.swift; sourceTree = ""; }; + 1CF65A822A42347D0042FFBD /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -112,6 +114,7 @@ 1CF65A552A3AA6800042FFBD /* Werkout-ios-Info.plist */, 1CF65A482A39FB910042FFBD /* JSON */, 1CF65A252A3972840042FFBD /* Werkout_iosApp.swift */, + 1CF65A822A42347D0042FFBD /* Extensions.swift */, 1CF65A272A3972840042FFBD /* Persistence.swift */, 1CF65A4F2A3A1EA90042FFBD /* BridgeModule.swift */, 1CF65A3F2A3973840042FFBD /* Views */, @@ -291,6 +294,7 @@ 1CF65A2D2A3972840042FFBD /* MainView.swift in Sources */, 1CF65A7D2A41275D0042FFBD /* Network.swift in Sources */, 1CF65A732A3F60D20042FFBD /* CreateExerciseActionsView.swift in Sources */, + 1CF65A832A42347D0042FFBD /* Extensions.swift in Sources */, 1CF65A282A3972840042FFBD /* Persistence.swift in Sources */, 1CF65A5B2A3BF4BE0042FFBD /* Equipment.swift in Sources */, 1CF65A452A39FB550042FFBD /* Exercise.swift in Sources */, diff --git a/Werkout_ios/APIModels/Exercise.swift b/Werkout_ios/APIModels/Exercise.swift index a4b1a87..9853b07 100644 --- a/Werkout_ios/APIModels/Exercise.swift +++ b/Werkout_ios/APIModels/Exercise.swift @@ -13,7 +13,7 @@ struct ExerciseElement: Codable { let weight: Int? let reps: Int? let duration: Int? - let durationAudio: String + let durationAudio: String? let weightAudio: String? let createdAt: String @@ -28,7 +28,7 @@ struct ExerciseElement: Codable { let df = DateFormatter() df.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" df.locale = Locale(identifier: "en_US_POSIX") - return df.date(from: self.createdAt ?? "") ?? Date() + return df.date(from: self.createdAt) ?? Date() } } diff --git a/Werkout_ios/APIModels/Workout.swift b/Werkout_ios/APIModels/Workout.swift index 938b319..55a86e8 100644 --- a/Werkout_ios/APIModels/Workout.swift +++ b/Werkout_ios/APIModels/Workout.swift @@ -12,7 +12,7 @@ struct Workout: Codable { let name: String let description: String? let exercises: [ExerciseElement] - let registeredUser: RegisteredUser + let registeredUser: RegisteredUser? enum CodingKeys: String, CodingKey { case name, description, exercises, id @@ -29,7 +29,7 @@ struct Workout: Codable { self.name = try container.decode(String.self, forKey: .name) self.description = try container.decodeIfPresent(String.self, forKey: .description) - self.registeredUser = try container.decode(RegisteredUser.self, forKey: .registeredUser) + self.registeredUser = try container.decodeIfPresent(RegisteredUser.self, forKey: .registeredUser) self.id = try container.decode(Int.self, forKey: .id) } diff --git a/Werkout_ios/BridgeModule.swift b/Werkout_ios/BridgeModule.swift index b038da9..a43540e 100644 --- a/Werkout_ios/BridgeModule.swift +++ b/Werkout_ios/BridgeModule.swift @@ -16,7 +16,7 @@ class BridgeModule: ObservableObject { var timerCompleted: (() -> Void)? @Published var currentExercise: ExerciseElement? - @Published var currentWorkout: Workout? + var currentWorkout: Workout? @Published var currentExerciseIdx: Int = -1 private func startTimerWith(duration: Int) { diff --git a/Werkout_ios/Extensions.swift b/Werkout_ios/Extensions.swift new file mode 100644 index 0000000..e497220 --- /dev/null +++ b/Werkout_ios/Extensions.swift @@ -0,0 +1,31 @@ +// +// Extensions.swift +// Werkout_ios +// +// Created by Trey Tartt on 6/20/23. +// + +import Foundation + +extension Dictionary { + func percentEncoded() -> Data? { + map { key, value in + let escapedKey = "\(key)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? "" + let escapedValue = "\(value)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? "" + return escapedKey + "=" + escapedValue + } + .joined(separator: "&") + .data(using: .utf8) + } +} + +extension CharacterSet { + static let urlQueryValueAllowed: CharacterSet = { + let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4 + let subDelimitersToEncode = "!$&'()*+,;=" + + var allowed: CharacterSet = .urlQueryAllowed + allowed.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)") + return allowed + }() +} diff --git a/Werkout_ios/Network/Fetchables.swift b/Werkout_ios/Network/Fetchables.swift index fa19d7d..e132b8e 100644 --- a/Werkout_ios/Network/Fetchables.swift +++ b/Werkout_ios/Network/Fetchables.swift @@ -35,3 +35,14 @@ class AllExerciseFetchable: Fetchable { typealias Response = [ExerciseExercise] var endPoint: String = "exercise/all/" } + +class CreateWorkoutFetchable: Postable { + var postableData: [String : Any]? + + typealias Response = Workout + var endPoint: String = "workout/create/" + + init(postData: [String: Any]) { + self.postableData = postData + } +} diff --git a/Werkout_ios/Network/Network.swift b/Werkout_ios/Network/Network.swift index 8b4380d..0cef1ed 100644 --- a/Werkout_ios/Network/Network.swift +++ b/Werkout_ios/Network/Network.swift @@ -12,6 +12,8 @@ enum FetchableError: Error { case noData case decodeError(Error) case endOfFileError + case noPostData + case statusError(Int) } protocol Fetchable { @@ -19,10 +21,13 @@ protocol Fetchable { var baseURL: String { get } var endPoint: String { get } - func fetch(completion: @escaping (Result) -> Void) } +protocol Postable: Fetchable { + var postableData: [String: Any]? { get } +} + extension Fetchable { var baseURL: String { "http://127.0.0.1:8000/" @@ -54,3 +59,53 @@ extension Fetchable { task.resume() } } + +extension Postable { + func fetch(completion: @escaping (Result) -> Void) { + guard let postableData = postableData else { + completion(.failure(.noPostData)) + return + } + + let url = URL(string: baseURL+endPoint)! + + let postData = try! JSONSerialization.data(withJSONObject:postableData) + + var request = URLRequest(url: url,timeoutInterval: Double.infinity) + request.addValue("Token fd59cbf6f5db98726e896cdb6b095ecb9c43a592", forHTTPHeaderField: "Authorization") + request.addValue("application/json", forHTTPHeaderField: "Content-Type") + + request.httpMethod = "POST" + request.httpBody = postData + + let task = URLSession.shared.dataTask(with: request, completionHandler: { data, response, error in + if let error = error { + completion(.failure(.apiError(error))) + return + } + + if let httpRespone = response as? HTTPURLResponse { + if httpRespone.statusCode != 201 { + completion(.failure(.statusError(httpRespone.statusCode))) + return + } + } + + guard let data = data else { + completion(.failure(.noData)) + return + } + + do { + let model = try JSONDecoder().decode(Response.self, from: data) + completion(.success(model)) + return + } catch { + completion(.failure(.decodeError(error))) + return + } + }) + + task.resume() + } +} diff --git a/Werkout_ios/Views/AddExerciseView.swift b/Werkout_ios/Views/AddExerciseView.swift index d5c697d..c1e3f40 100644 --- a/Werkout_ios/Views/AddExerciseView.swift +++ b/Werkout_ios/Views/AddExerciseView.swift @@ -16,7 +16,7 @@ struct AddExerciseView: View { @State var searchString: String = "" - @EnvironmentObject var bridgeModule: BridgeModule + @StateObject var bridgeModule = BridgeModule.shared @Environment(\.dismiss) var dismiss var selectedWorkout: ((ExerciseExercise) -> Void) @@ -62,6 +62,8 @@ struct AddExerciseView: View { }.frame(height: 100) } + Divider() + if let equipment = DataStore.shared.allEquipment { Button("toggle all", action: { if self.selectedEquipment.count > 0 { @@ -100,12 +102,16 @@ struct AddExerciseView: View { }.frame(height: 100) } + Divider() + TextField("Filter", text: $searchString) .onReceive(Just(searchString)) { location in filterExercises() } .padding() + Divider() + List() { ForEach(filteredExercises.indices, id: \.self) { i in let obj = filteredExercises[i] @@ -142,6 +148,7 @@ struct AddExerciseView: View { selectedEquipment = equipment filteredExercises = exercises } + .background(Color(uiColor: .tertiarySystemBackground)) } func filterExercises() { diff --git a/Werkout_ios/Views/AllWorkoutsView.swift b/Werkout_ios/Views/AllWorkoutsView.swift index 1ec6015..c131f2d 100644 --- a/Werkout_ios/Views/AllWorkoutsView.swift +++ b/Werkout_ios/Views/AllWorkoutsView.swift @@ -10,15 +10,19 @@ import SwiftUI struct AllWorkoutsView: View { @State var workouts: [Workout]? - @EnvironmentObject var bridgeModule: BridgeModule + var bridgeModule = BridgeModule.shared + @State public var needsUpdating: Bool = true + @State private var showWorkoutDetail = false @State private var selectedWorkout: Workout? { didSet { + bridgeModule.currentWorkout = selectedWorkout showWorkoutDetail = true - bridgeModule.currentWorkout = self.selectedWorkout } } + let pub = NotificationCenter.default.publisher(for: NSNotification.Name("CreatedNewWorkout")) + var body: some View { ZStack { if let workouts = workouts { @@ -33,7 +37,7 @@ struct AllWorkoutsView: View { } .contentShape(Rectangle()) .onTapGesture { - selectedItem(workout: workout) + selectedWorkout = workout } } } @@ -41,16 +45,19 @@ struct AllWorkoutsView: View { Text("no workouts") } }.onAppear{ - AllWorkoutFetchable().fetch(completion: { result in - switch result { - case .success(let model): - DispatchQueue.main.async { - self.workouts = model + if needsUpdating { + AllWorkoutFetchable().fetch(completion: { result in + needsUpdating = false + switch result { + case .success(let model): + DispatchQueue.main.async { + self.workouts = model + } + case .failure(let failure): + fatalError("shit broke") } - case .failure(let failure): - fatalError("shit broke") - } - }) + }) + } } .sheet(isPresented: $showWorkoutDetail) { if let selectedWorkout = selectedWorkout { @@ -58,12 +65,11 @@ struct AllWorkoutsView: View { WorkoutDetailView(viewModel: viewModel) } } + .onReceive(pub) { (output) in + self.needsUpdating = true + } } - - func selectedItem(workout: Workout) { - selectedWorkout = workout - } - + func testParse() { if let filepath = Bundle.main.path(forResource: "AllWorkouts", ofType: "json") { do { diff --git a/Werkout_ios/Views/CreateWorkoutViews/CreateViewModels.swift b/Werkout_ios/Views/CreateWorkoutViews/CreateViewModels.swift index 29e888f..411a12c 100644 --- a/Werkout_ios/Views/CreateWorkoutViews/CreateViewModels.swift +++ b/Werkout_ios/Views/CreateWorkoutViews/CreateViewModels.swift @@ -95,4 +95,29 @@ class WorkoutViewModel: ObservableObject { superSets.remove(at: idx) } } + + func uploadWorkout() { + var exercises = [[String: Any]]() + superSets.forEach({ superset in + for _ in 0 ..< superset.numberOfRounds { + for exercise in superset.exercises { + let item = ["id": exercise.exercise.id, "reps": exercise.reps, "weight": exercise.weight, "duration": exercise.duration] as [String : Any] + exercises.append(item) + } + } + }) + let uploadBody = ["name": title, "description": "description", "exercise_data": exercises] as [String : Any] + CreateWorkoutFetchable(postData: uploadBody).fetch(completion: { result in + DispatchQueue.main.async { + switch result { + case .success(_): + self.superSets.removeAll() + self.title = "" + NotificationCenter.default.post(name: NSNotification.Name("CreatedNewWorkout"), object: nil, userInfo: nil) + case .failure(let failure): + print(failure) + } + } + }) + } } diff --git a/Werkout_ios/Views/CreateWorkoutViews/CreateWorkoutMainView.swift b/Werkout_ios/Views/CreateWorkoutViews/CreateWorkoutMainView.swift index 820f63c..3b088dd 100644 --- a/Werkout_ios/Views/CreateWorkoutViews/CreateWorkoutMainView.swift +++ b/Werkout_ios/Views/CreateWorkoutViews/CreateWorkoutMainView.swift @@ -32,7 +32,7 @@ struct CreateWorkoutMainView: View { Divider() Button("Done", action: { - + viewModel.uploadWorkout() }) .frame(maxWidth: .infinity, alignment: .center) .frame(height: 44) diff --git a/Werkout_ios/Views/ExternalWorkoutDetailView.swift b/Werkout_ios/Views/ExternalWorkoutDetailView.swift index 2a8f9c1..70645f7 100644 --- a/Werkout_ios/Views/ExternalWorkoutDetailView.swift +++ b/Werkout_ios/Views/ExternalWorkoutDetailView.swift @@ -9,8 +9,7 @@ import SwiftUI import AVKit struct ExternalWorkoutDetailView: View { - @EnvironmentObject var bridgeModule: BridgeModule - @State var player = AVPlayer() + @StateObject var bridgeModule = BridgeModule.shared var body: some View { if let workout = bridgeModule.currentWorkout { @@ -21,76 +20,88 @@ struct ExternalWorkoutDetailView: View { .frame(width: metrics.size.width, height: metrics.size.height * 0.1) HStack { - VideoPlayer(player: player) - .onChange(of: bridgeModule.currentExerciseIdx, perform: { newValue in - updateVideo() - }) + if let currentExercise = bridgeModule.currentExercise { + VideoPlayerView(currentExercise: currentExercise.exercise) + .frame(width: metrics.size.width * 0.6, height: metrics.size.height * 0.7) + } - if let workout = bridgeModule.currentWorkout { - List() { - ForEach(workout.exercisesSortedByCreated_at.indices, id: \.self) { i in - let obj = workout.exercisesSortedByCreated_at[i] - HStack { - if let _ = bridgeModule.currentExercise { - if i == bridgeModule.currentExerciseIdx { - Image(systemName: "checkmark") - .font(Font.system(size: 75)) - .foregroundColor(.green) - } - } - - Text(obj.exercise.name ?? "") - .font(Font.system(size: 75)) - .padding() - } - } - } - .frame(width: metrics.size.width * 0.4) - } + ExtExerciseList(workout: workout, + currentExerciseIdx: bridgeModule.currentExerciseIdx) + .frame(width: metrics.size.width * 0.4, height: metrics.size.height * 0.7) } - .frame(width: metrics.size.width, height: metrics.size.height * 0.7) - HStack { - if let currenExercise = bridgeModule.currentExercise { - VStack { - Text(currenExercise.exercise.name ?? "") - .font(Font.system(size: 100)) - .frame(maxWidth: .infinity, alignment: .leading) - - HStack { - if let duration = currenExercise.duration { - ProgressView(value: Float(bridgeModule.timeLeft), total: Float(duration)) - .scaleEffect(x: 1, y: 6, anchor: .center) - Text("\(bridgeModule.timeLeft)") - .font(Font.system(size: 75)) - .padding(.leading) - } else if let reps = currenExercise.reps { - Text("\(reps)") - } - } - .padding([.leading, .trailing], 50) - } - } - } - .frame(width: metrics.size.width, height: metrics.size.height * 0.2) - .padding([.leading, .trailing]) + ExtCountdownView() + .frame(width: metrics.size.width-50, height: metrics.size.height * 0.2) + .padding([.leading, .trailing], 50) } } } } +} + +struct ExtExerciseList: View { + var workout: Workout + var currentExerciseIdx: Int - func updateVideo() { - if let videoURL = bridgeModule.currentExercise?.exercise.videoURL { - // let completeURL = "http://127.0.0.1:8000" + videoURL - player = AVPlayer(url: Bundle.main.url(forResource: "Straight_Leg_Sit_Up", withExtension: "mp4")!) - player.play() - // print(completeURL) - // player = AVPlayer(url: URL(string: completeURL)!) - // player.play() + var body: some View { + List() { + ForEach(workout.exercisesSortedByCreated_at.indices, id: \.self) { i in + let obj = workout.exercisesSortedByCreated_at[i] + HStack { + if i == currentExerciseIdx { + Image(systemName: "checkmark") + .font(Font.system(size: 75)) + .foregroundColor(.green) + } + + Text(obj.exercise.name) + .font(Font.system(size: 75)) + .padding() + } + } } } } +struct ExtCountdownView: View { + @StateObject var bridgeModule = BridgeModule.shared + + var body: some View { + VStack { + if let currenExercise = bridgeModule.currentExercise { + Text(currenExercise.exercise.name) + .font(Font.system(size: 100)) + .frame(maxWidth: .infinity, alignment: .leading) + + HStack { + if let duration = currenExercise.duration { + ProgressView(value: Float(bridgeModule.timeLeft), total: Float(duration)) + .scaleEffect(x: 1, y: 6, anchor: .center) + Text("\(bridgeModule.timeLeft)") + .font(Font.system(size: 75)) + .padding(.leading) + } else if let reps = currenExercise.reps { + Text("\(reps)") + } + } + } + } + } +} + +struct VideoPlayerView: View { + var currentExercise: ExerciseExercise + @State var player = AVPlayer() + + var body: some View { + VideoPlayer(player: player) + .onAppear{ + player = AVPlayer(url: Bundle.main.url(forResource: "Straight_Leg_Sit_Up", withExtension: "mp4")!) + player.play() + } + } +} + struct ExternalWorkoutDetailView_Previews: PreviewProvider { static var bridge = BridgeModule.shared diff --git a/Werkout_ios/Views/MainView.swift b/Werkout_ios/Views/MainView.swift index dc27d6b..d838c93 100644 --- a/Werkout_ios/Views/MainView.swift +++ b/Werkout_ios/Views/MainView.swift @@ -10,7 +10,7 @@ import CoreData struct MainView: View { @State var workout: Workout? - @EnvironmentObject var bridgeModule: BridgeModule + @StateObject var bridgeModule = BridgeModule.shared var body: some View { ZStack { diff --git a/Werkout_ios/Views/WorkoutDetailView.swift b/Werkout_ios/Views/WorkoutDetailView.swift index 154ad07..953cdbf 100644 --- a/Werkout_ios/Views/WorkoutDetailView.swift +++ b/Werkout_ios/Views/WorkoutDetailView.swift @@ -8,11 +8,11 @@ import SwiftUI struct WorkoutDetailView: View { - @ObservedObject var viewModel: WorkoutDetailViewModel - @EnvironmentObject var bridgeModule: BridgeModule + @StateObject var viewModel: WorkoutDetailViewModel + var bridgeModule = BridgeModule.shared @Environment(\.dismiss) var dismiss - @State var selectedIdx = -1 { + @State var selectedIdx = 0 { didSet { runItemAt(idx: selectedIdx) } @@ -34,26 +34,16 @@ struct WorkoutDetailView: View { .background(.red) Button("ohhh lets do it", action: { + bridgeModule.currentWorkout = workout runItemAt(idx: 0) }) .frame(maxWidth: .infinity, maxHeight: .infinity) .background(.green) } .frame(height: 88) - List() { - ForEach(workout.exercisesSortedByCreated_at.indices, id: \.self) { i in - let obj = workout.exercisesSortedByCreated_at[i] - Text(obj.exercise.name ?? "") - .onTapGesture { selectedIdx = i } - } - } - - if let duration = bridgeModule.currentExercise?.duration { - HStack { - ProgressView(value: Float(bridgeModule.timeLeft), total: Float(duration)) - Text("\(bridgeModule.timeLeft)") - }.padding(16) - } + + ExerciseListView(workout: workout) + CountdownView() } .onAppear{ bridgeModule.timerCompleted = { @@ -63,9 +53,8 @@ struct WorkoutDetailView: View { .interactiveDismissDisabled() } } - } - + func runItemAt(idx: Int) { switch viewModel.status { case .showWorkout(let workout): @@ -86,6 +75,36 @@ struct WorkoutDetailView: View { } } +struct ExerciseListView: View { + @ObservedObject var bridgeModule = BridgeModule.shared + var workout: Workout + + var body: some View { + List() { + ForEach(workout.exercisesSortedByCreated_at.indices, id: \.self) { i in + let obj = workout.exercisesSortedByCreated_at[i] + Text(obj.exercise.name) + // .onTapGesture { selectedIdx = i } + } + } + } +} + +struct CountdownView: View { + @StateObject var bridgeModule = BridgeModule.shared + + var body: some View { + VStack { + if let duration = bridgeModule.currentExercise?.duration { + HStack { + ProgressView(value: Float(bridgeModule.timeLeft), total: Float(duration)) + Text("\(bridgeModule.timeLeft)") + }.padding(16) + } + } + } +} + struct WorkoutDetailView_Previews: PreviewProvider { static var previews: some View { WorkoutDetailView(viewModel: WorkoutDetailViewModel(workout: PreviewWorkout.workout())) diff --git a/Werkout_ios/Werkout_iosApp.swift b/Werkout_ios/Werkout_iosApp.swift index afe076b..834ff20 100644 --- a/Werkout_ios/Werkout_iosApp.swift +++ b/Werkout_ios/Werkout_iosApp.swift @@ -11,8 +11,10 @@ import Combine @main struct Werkout_iosApp: App { let persistenceController = PersistenceController.shared - @ObservedObject var bridgeModule = BridgeModule.shared @State var additionalWindows: [UIWindow] = [] + @State private var tabSelection = 1 + + let pub = NotificationCenter.default.publisher(for: NSNotification.Name("CreatedNewWorkout")) private var screenDidConnectPublisher: AnyPublisher { NotificationCenter.default @@ -32,9 +34,8 @@ struct Werkout_iosApp: App { var body: some Scene { WindowGroup { - TabView { + TabView(selection: $tabSelection) { AllWorkoutsView() - .environmentObject(bridgeModule) .onReceive( screenDidConnectPublisher, perform: screenDidConnect @@ -46,25 +47,32 @@ struct Werkout_iosApp: App { .tabItem { Label("All Workouts", systemImage: "figure.strengthtraining.traditional") } + .tag(1) + CreateWorkoutMainView() .tabItem { Label("Create Workout", systemImage: "plus.app.fill") } + .tag(2) AccountView() .tabItem { Label("Accounts", systemImage: "person.fill.turn.down") } + .tag(3) } .onAppear{ DataStore.shared.fetchAllData() } + .onReceive(pub) { (output) in + self.tabSelection = 1 + } } } private func screenDidDisconnect(_ screen: UIScreen) { additionalWindows.removeAll { $0.screen == screen } - bridgeModule.isShowingOnExternalDisplay = false + BridgeModule.shared.isShowingOnExternalDisplay = false } private func screenDidConnect(_ screen: UIScreen) { @@ -75,11 +83,10 @@ struct Werkout_iosApp: App { as? UIWindowScene let view = ExternalWorkoutDetailView() - .environmentObject(bridgeModule) let controller = UIHostingController(rootView: view) window.rootViewController = controller window.isHidden = false additionalWindows.append(window) - bridgeModule.isShowingOnExternalDisplay = true + BridgeModule.shared.isShowingOnExternalDisplay = true } }