diff --git a/Neuro App/HomeView.swift b/Neuro App/HomeView.swift index c1bb241..ca41b6b 100644 --- a/Neuro App/HomeView.swift +++ b/Neuro App/HomeView.swift @@ -92,21 +92,38 @@ struct HomeView: View { .padding(.top, 10) Spacer() - - // NIH Forms Button - Button(action: { - path.append("savedForms") - }) { - Text("NIH Forms") - .font(.headline) - .foregroundColor(adaptiveColor()) - .padding() - .frame(maxWidth: .infinity) - .background(adaptiveBackground()) - .cornerRadius(10) + + HStack(spacing:0) { + // Sessions Button + Button(action: { + path.append("sessions") + }) { + Text("Sessions") + .font(.headline) + .foregroundColor(adaptiveColor()) + .padding() + .frame(maxWidth: .infinity) + .background(adaptiveBackground()) + .cornerRadius(10) + } + .padding(.horizontal) + .padding(.bottom, 20) + + // NIH Forms Button + Button(action: { + path.append("savedForms") + }) { + Text("NIH Forms") + .font(.headline) + .foregroundColor(adaptiveColor()) + .padding() + .frame(maxWidth: .infinity) + .background(adaptiveBackground()) + .cornerRadius(10) + } + .padding(.horizontal) + .padding(.bottom, 20) } - .padding(.horizontal) - .padding(.bottom, 20) } // Navigation destination @@ -114,6 +131,8 @@ struct HomeView: View { switch route { case "savedForms": SavedFormsView(navigationPath: $path) + case "sessions": + SavedSessionsView(navigationPath: $path) default: EmptyView() } diff --git a/Neuro App/RemoteSessionsManager.swift b/Neuro App/RemoteSessionsManager.swift new file mode 100644 index 0000000..7e14dc3 --- /dev/null +++ b/Neuro App/RemoteSessionsManager.swift @@ -0,0 +1,30 @@ +// +// RemoteSessions.swift +// Neurology-iOS-Client-App +// +// Created by Edris Afzali on 10/21/25. +// + +import Foundation + +struct RemoteSession: Identifiable, Codable, Hashable { + var id: UUID = UUID() + var name: String + var sessionDate: Date + // Optional session notes + var notes: String = "" +} + +enum SessionManager { + // Replace with network call later + static func fetchSessionsFromServer(completion: @escaping ([RemoteSession]) -> Void) { + // Simulated network delay + SAMPLE data for now + DispatchQueue.global().asyncAfter(deadline: .now() + 0.3) { + let samples: [RemoteSession] = [ + RemoteSession(name: "Sample session 1", sessionDate: Date(), notes: "Blah blah blah."), + RemoteSession(name: "Sample session 2", sessionDate: Date().addingTimeInterval(-86400), notes: "Testing notes attribute.") + ] + completion(samples) + } + } +} diff --git a/Neuro App/SavedSessionsView.swift b/Neuro App/SavedSessionsView.swift new file mode 100644 index 0000000..d18f306 --- /dev/null +++ b/Neuro App/SavedSessionsView.swift @@ -0,0 +1,164 @@ +// +// SessionsView.swift +// Neurology-iOS-Client-App +// +// Created by Edris Afzali on 10/14/25. +// + +import SwiftUI + +struct SavedSessionsView: View { + + @Binding var navigationPath: NavigationPath + + // Mirror your NIH pattern: an inner store that publishes an array + @StateObject var sessionStore = RemoteSessionStore() + + // Routes mirror your FormRoute style + enum SessionRoute: Hashable { + case new + case detail(session: RemoteSession) + } + + // Simple store like your RemoteFormStore + class RemoteSessionStore: ObservableObject { + @Published var sessions: [RemoteSession] = [] + } + + var body: some View { + ZStack { + LinearGradient(colors: [.gray, .white, .gray], + startPoint: .topLeading, + endPoint: .bottomTrailing) + .edgesIgnoringSafeArea(.all) + + ScrollView { + VStack(spacing: 20) { + + // Header + VStack { + HStack { + Button(action: { + navigationPath.removeLast() + }) { + HStack { + Image(systemName: "chevron.left") + Text("Back") + } + .foregroundColor(.black) + .font(.title3) + } + + Spacer() + + Button(action: { + navigationPath.append(SessionRoute.new) + }) { + Text("New Session") + .foregroundColor(.black) + .font(.title3) + } + } + .padding(.horizontal) + .padding(.top) + + Text("Saved Sessions") + .font(.largeTitle) + .bold() + .foregroundColor(.black) + .padding(.leading) + .padding(.top, 5) + .frame(maxWidth: .infinity, alignment: .leading) + } + + // Session List + VStack(spacing: 15) { + ForEach(sessionStore.sessions) { session in + HStack { + VStack(alignment: .leading, spacing: 5) { + Text(session.name) + .font(.headline) + .foregroundColor(Color(UIColor { $0.userInterfaceStyle == .dark ? .white : .black })) + + Text("Date: \(session.sessionDate, style: .date)") + .font(.subheadline) + .foregroundColor(Color(UIColor { $0.userInterfaceStyle == .dark ? .white : .black })) + } + + Spacer() + + Button(action: { + navigationPath.append(SessionRoute.detail(session: session)) + }) { + Text("View") + .font(.subheadline) + .foregroundColor(.black) + .padding(.vertical, 6) + .padding(.horizontal, 10) + .background(Color.white) + .cornerRadius(8) + .overlay( + RoundedRectangle(cornerRadius: 8) + .stroke(Color.gray, lineWidth: 1) + ) + } + } + .padding() + .background(Color(UIColor { $0.userInterfaceStyle == .dark ? .black : .white })) + .cornerRadius(10) + .shadow(radius: 5) + } + } + .padding(.horizontal) + .padding(.bottom, 20) + } + } + .navigationBarBackButtonHidden(true) + .onAppear { + // Fetch sessions on appear + SessionManager.fetchSessionsFromServer { fetched in + DispatchQueue.main.async { + sessionStore.sessions = fetched + } + } + } + } + .navigationDestination(for: SessionRoute.self) { route in + switch route { + case .new: + NewSessionView_Skeleton(navigationPath: $navigationPath) + + case .detail(let session): + SavedSessionDetailView_Skeleton(navigationPath: $navigationPath, session: session) + } + } + } +} + +// Temporary stub for compilation +struct NewSessionView_Skeleton: View { + @Binding var navigationPath: NavigationPath + var body: some View { + VStack(spacing: 16) { + Text("New Session (Skeleton)") + .font(.title2) + Button("Done") { navigationPath.removeLast() } + } + .padding() + } +} + +struct SavedSessionDetailView_Skeleton: View { + @Binding var navigationPath: NavigationPath + let session: RemoteSession + var body: some View { + VStack(spacing: 16) { + Text("Session Detail (Skeleton)") + .font(.title2) + Text(session.name) + Text(session.sessionDate.formatted(date: .abbreviated, time: .shortened)) + Button("Back") { navigationPath.removeLast() } + } + .padding() + } +} diff --git a/Neurology-iOS-Client-App.xcodeproj/project.pbxproj b/Neurology-iOS-Client-App.xcodeproj/project.pbxproj index bcc223d..3ee7f9c 100644 --- a/Neurology-iOS-Client-App.xcodeproj/project.pbxproj +++ b/Neurology-iOS-Client-App.xcodeproj/project.pbxproj @@ -33,6 +33,8 @@ 60140A712CAEE2F400E61908 /* SavedFormDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60140A702CAEE2F400E61908 /* SavedFormDetailView.swift */; }; 60B7690B2C9B818C00CC8343 /* StrokeScaleFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60B7690A2C9B818100CC8343 /* StrokeScaleFormView.swift */; }; 60B7690F2CA32CE000CC8343 /* SavedFormsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60B7690E2CA32CD500CC8343 /* SavedFormsView.swift */; }; + CD108BF12EA83209005B6592 /* RemoteSessionsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD108BF02EA83202005B6592 /* RemoteSessionsManager.swift */; }; + CDFB4CCC2E9EF9ED005010B4 /* SavedSessionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDFB4CCB2E9EF9E9005010B4 /* SavedSessionsView.swift */; }; D4F7ECA02D03989400C356C8 /* NewNIHFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4F7EC9F2D03988B00C356C8 /* NewNIHFormView.swift */; }; D4F9BEE92DCA6EF800C6BC4D /* AuthViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4F9BEE82DCA6EED00C6BC4D /* AuthViewModel.swift */; }; D4F9BEEB2DCA723400C6BC4D /* KeyChainHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4F9BEEA2DCA722F00C6BC4D /* KeyChainHelper.swift */; }; @@ -91,6 +93,8 @@ 60B7690E2CA32CD500CC8343 /* SavedFormsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavedFormsView.swift; sourceTree = ""; }; 60E860F62C5192DE0097826E /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = ""; }; 60F68C252C5ABB3D00933EE3 /* CallView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallView.swift; sourceTree = ""; }; + CD108BF02EA83202005B6592 /* RemoteSessionsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteSessionsManager.swift; sourceTree = ""; }; + CDFB4CCB2E9EF9E9005010B4 /* SavedSessionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavedSessionsView.swift; sourceTree = ""; }; D4F7EC9F2D03988B00C356C8 /* NewNIHFormView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewNIHFormView.swift; sourceTree = ""; }; D4F9BEE82DCA6EED00C6BC4D /* AuthViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthViewModel.swift; sourceTree = ""; }; D4F9BEEA2DCA722F00C6BC4D /* KeyChainHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyChainHelper.swift; sourceTree = ""; }; @@ -120,6 +124,8 @@ 088B345C2C5C023F00094A02 /* Neuro App */ = { isa = PBXGroup; children = ( + CD108BF02EA83202005B6592 /* RemoteSessionsManager.swift */, + CDFB4CCB2E9EF9E9005010B4 /* SavedSessionsView.swift */, D4F9BEEC2DCA9BCD00C6BC4D /* StrokeScaleFormManager.swift */, 08FE5DC72DDCFD9100361EBF /* localDevelopment.xcconfig */, 08FE5DCB2DDD041E00361EBF /* Release.xcconfig */, @@ -369,6 +375,7 @@ 088B348E2C5C03A000094A02 /* Neuro_AppApp.swift in Sources */, 0813C0B82C6159A200CF5C70 /* Config.swift in Sources */, 08FE5DCA2DDCFFB100361EBF /* AppURLs.swift in Sources */, + CDFB4CCC2E9EF9ED005010B4 /* SavedSessionsView.swift in Sources */, 0813C0B42C6159A200CF5C70 /* WebRTCClient.swift in Sources */, 60140A712CAEE2F400E61908 /* SavedFormDetailView.swift in Sources */, 0813C0B52C6159A200CF5C70 /* API.swift in Sources */, @@ -376,6 +383,7 @@ D4F9BEE92DCA6EF800C6BC4D /* AuthViewModel.swift in Sources */, 60140A6B2CAED8BB00E61908 /* NeuroDataModel.xcdatamodeld in Sources */, 60B7690F2CA32CE000CC8343 /* SavedFormsView.swift in Sources */, + CD108BF12EA83209005B6592 /* RemoteSessionsManager.swift in Sources */, 08A99ED52C6297E20046D4A7 /* SignInView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0;