diff --git a/Asthmaguard.xcodeproj/project.pbxproj b/Asthmaguard.xcodeproj/project.pbxproj index 6e4f28c..6278a04 100644 --- a/Asthmaguard.xcodeproj/project.pbxproj +++ b/Asthmaguard.xcodeproj/project.pbxproj @@ -46,6 +46,9 @@ 12E0B0922BF60F89003E18D6 /* AnalyticsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E0B0912BF60F89003E18D6 /* AnalyticsView.swift */; }; 12EAA2DE2BE8C50400C0A1DB /* LocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12EAA2DD2BE8C50400C0A1DB /* LocationManager.swift */; }; 12EEFB042BB05FF3003053AB /* SettingsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12EEFB032BB05FF2003053AB /* SettingsScreen.swift */; }; + 12FC1DF42C03ABA70002F50D /* AsthmaTriggerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12FC1DF32C03ABA70002F50D /* AsthmaTriggerModel.swift */; }; + 12FC1DFC2C044CA30002F50D /* SessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12FC1DFB2C044CA30002F50D /* SessionManager.swift */; }; + 12FC1DFE2C0450BE0002F50D /* AsthmaThreatModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12FC1DFD2C0450BE0002F50D /* AsthmaThreatModel.swift */; }; 36495D3769F738E52AE09E55 /* Pods_AsthmaguardTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A473D07D19F4891C0EC3EA46 /* Pods_AsthmaguardTests.framework */; }; 3FF0674C489C293D17AD478C /* Pods_Asthmaguard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D86664A7B056AD9D5A4532B /* Pods_Asthmaguard.framework */; }; /* End PBXBuildFile section */ @@ -104,6 +107,9 @@ 12E0B0912BF60F89003E18D6 /* AnalyticsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsView.swift; sourceTree = ""; }; 12EAA2DD2BE8C50400C0A1DB /* LocationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationManager.swift; sourceTree = ""; }; 12EEFB032BB05FF2003053AB /* SettingsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreen.swift; sourceTree = ""; }; + 12FC1DF32C03ABA70002F50D /* AsthmaTriggerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsthmaTriggerModel.swift; sourceTree = ""; }; + 12FC1DFB2C044CA30002F50D /* SessionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionManager.swift; sourceTree = ""; }; + 12FC1DFD2C0450BE0002F50D /* AsthmaThreatModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsthmaThreatModel.swift; sourceTree = ""; }; 47517DB559739E3571B31F22 /* Pods-AsthmaguardTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsthmaguardTests.debug.xcconfig"; path = "Target Support Files/Pods-AsthmaguardTests/Pods-AsthmaguardTests.debug.xcconfig"; sourceTree = ""; }; 5810EE9B8C5719A14118CF19 /* Pods-AsthmaguardTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsthmaguardTests.release.xcconfig"; path = "Target Support Files/Pods-AsthmaguardTests/Pods-AsthmaguardTests.release.xcconfig"; sourceTree = ""; }; 711CB4D76AD25FABB75C23A2 /* Pods-Asthmaguard.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Asthmaguard.debug.xcconfig"; path = "Target Support Files/Pods-Asthmaguard/Pods-Asthmaguard.debug.xcconfig"; sourceTree = ""; }; @@ -218,9 +224,7 @@ 1276E3702B7ACD8F002CBACB /* Data */ = { isa = PBXGroup; children = ( - 12E1EDEE2B95A9870016EDDE /* Responses */, 12E1EDEB2B95A9270016EDDE /* Models */, - 12E1EDE92B95A8FF0016EDDE /* Repos */, ); path = Data; sourceTree = ""; @@ -228,6 +232,7 @@ 1276E3722B7ACD99002CBACB /* Business */ = { isa = PBXGroup; children = ( + 12FC1DFB2C044CA30002F50D /* SessionManager.swift */, 12EAA2DD2BE8C50400C0A1DB /* LocationManager.swift */, 12E1EDE82B95A73B0016EDDE /* Usecases */, ); @@ -302,16 +307,11 @@ path = Usecases; sourceTree = ""; }; - 12E1EDE92B95A8FF0016EDDE /* Repos */ = { - isa = PBXGroup; - children = ( - ); - path = Repos; - sourceTree = ""; - }; 12E1EDEB2B95A9270016EDDE /* Models */ = { isa = PBXGroup; children = ( + 12FC1DF32C03ABA70002F50D /* AsthmaTriggerModel.swift */, + 12FC1DFD2C0450BE0002F50D /* AsthmaThreatModel.swift */, ); path = Models; sourceTree = ""; @@ -332,13 +332,6 @@ path = DataNetwork; sourceTree = ""; }; - 12E1EDEE2B95A9870016EDDE /* Responses */ = { - isa = PBXGroup; - children = ( - ); - path = Responses; - sourceTree = ""; - }; 12E1EDEF2B95A9BD0016EDDE /* Endpoints */ = { isa = PBXGroup; children = ( @@ -545,7 +538,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 12FC1DF42C03ABA70002F50D /* AsthmaTriggerModel.swift in Sources */, 12C3F7D22BB576C6008B43ED /* CustomBioData.swift in Sources */, + 12FC1DFC2C044CA30002F50D /* SessionManager.swift in Sources */, 12EEFB042BB05FF3003053AB /* SettingsScreen.swift in Sources */, 121A50D72BBA364500198997 /* BreathingExerciseScreen.swift in Sources */, 1236025C2BD8E1A700A2C657 /* DatabaseSetUp.swift in Sources */, @@ -567,6 +562,7 @@ 12E0B0922BF60F89003E18D6 /* AnalyticsView.swift in Sources */, 126FC27C2BA30B1B00BE1FDD /* DashboardView.swift in Sources */, 12E0B0902BF60EBE003E18D6 /* CompanionSettingScreen.swift in Sources */, + 12FC1DFE2C0450BE0002F50D /* AsthmaThreatModel.swift in Sources */, 12BAFE2A2BA0428E003E7980 /* SurveyHelper.swift in Sources */, 121A50D92BBA401600198997 /* CustomTabView.swift in Sources */, 12E0B08E2BF60E5E003E18D6 /* CompanionDashboardView.swift in Sources */, diff --git a/Asthmaguard/Business/SessionManager.swift b/Asthmaguard/Business/SessionManager.swift new file mode 100644 index 0000000..fd47b84 --- /dev/null +++ b/Asthmaguard/Business/SessionManager.swift @@ -0,0 +1,26 @@ +// +// SessionManager.swift +// Asthmaguard +// +// Created by Sadeel Muwahed on 27/05/2024. +// + +class SessionManager { + static let shared = SessionManager() + + private var currentToken: Int? + + private init() { } + + func login(token: Int) { + self.currentToken = token + } + + func logout() { + self.currentToken = nil + } + + func getCurrentToken() -> Int? { + return self.currentToken + } +} diff --git a/Asthmaguard/Business/Usecases/AsthmaThreatCalculator.swift b/Asthmaguard/Business/Usecases/AsthmaThreatCalculator.swift index 1621d31..86c4192 100644 --- a/Asthmaguard/Business/Usecases/AsthmaThreatCalculator.swift +++ b/Asthmaguard/Business/Usecases/AsthmaThreatCalculator.swift @@ -9,12 +9,29 @@ import Foundation import CoreLocation import HealthKit -class AsthmaThreatCalculatorUseCase { +public class AsthmaThreatCalculatorUseCase { private let locationManager = LocationManager.shared private let weatherKitData = WeatherKitData() private let healthStore = HKHealthStore() private let databaseManager = DatabaseManager.shared + + var weightedEnvironmentalRisk: Double = 0.0 + var weightedBioSignalRisk: Double = 0.0 + + var weightedHeartRateSeverity: Double = 0.0 + var weightedRespiratoryRateSeverity: Double = 0.0 + var weightedOxygenSaturationSeverity: Double = 0.0 + var weightedAirQualitySeverity: Double = 0.0 + var weightedPollenSeverity: Double = 0.0 + var weightedHumiditySeverity: Double = 0.0 + var weightedCloudCoverSeverity: Double = 0.0 + var weightedTemperatureSeverity: Double = 0.0 + var totalWeightedSeverity: Double = 0.0 + init() { + startMonitoring() + } + // MARK: - Monitoring func startMonitoring() { @@ -25,36 +42,60 @@ class AsthmaThreatCalculatorUseCase { // MARK: - Data Fetching - private func fetchDataAndCalculateAsthmaSeverity() { - self.fetchBiosignalData { biosignalSamples in - guard let biosignalSamples = biosignalSamples else { - print("Failed to fetch biosignal data.") + func fetchDataAndCalculateAsthmaSeverity() { + guard let patientToken = getPatientToken() else { + print("Current token not available.") + return + } + + databaseManager.fetchUserID(byToken: patientToken) { userID in + guard let userID = userID else { + print("User ID not found for token: \(patientToken).") + return + } + + self.fetchBiosignalData { biosignalSamples in + guard let biosignalSamples = biosignalSamples else { + print("Failed to fetch biosignal data.") + return + } + + self.fetchEnvironmentalData { airQualityData, pollenForecastData in + guard let airQualityData = airQualityData, let pollenForecastData = pollenForecastData else { + print("Failed to fetch environmental data.") + return + } + + self.fetchWeatherData { weatherData in + guard let weatherData = weatherData else { + print("Failed to fetch weather data.") + return + } + + self.calculateAsthmaSeverity(userID: userID, biosignalSamples: biosignalSamples, environmentalData: (airQualityData, pollenForecastData), weatherData: weatherData) + } + } + } + } + } + + func fetchData() { + guard let patientToken = getPatientToken() else { + print("Current username not available.") + return + } + + databaseManager.fetchUserID(byToken: patientToken) { userID in + guard let userID = userID else { + print("User ID not found for username: \(patientToken).") return } - self.fetchEnvironmentalData { airQualityData, pollenForecastData in - guard let airQualityData = airQualityData, let pollenForecastData = pollenForecastData else { - print("Failed to fetch environmental data.") - return - } - - self.fetchWeatherData { weatherData in - guard let weatherData = weatherData else { - print("Failed to fetch weather data.") - return + self.fetchBiosignalData { biosignalSamples in + self.fetchEnvironmentalData { airQualityData, pollenForecastData in + self.fetchWeatherData { weatherData in + print("airQuality data \(String(describing: airQualityData)), pollenForecastData \(String(describing: pollenForecastData)), weatherData \(String(describing: weatherData)), bioSignalData \(String(describing: biosignalSamples))") } - - self.calculateAsthmaSeverity(biosignalSamples: biosignalSamples, environmentalData: (airQualityData, pollenForecastData), weatherData: weatherData) - } - } - } - } - - func fetchData() { - self.fetchBiosignalData { biosignalSamples in - self.fetchEnvironmentalData { airQualityData, pollenForecastData in - self.fetchWeatherData { weatherData in - print("airQuality data \(String(describing: airQualityData)), pollenForecastData \(String(describing: pollenForecastData)), weatherData \(String(describing: weatherData)), bioSignalData \(String(describing: biosignalSamples))") } } } @@ -120,36 +161,59 @@ class AsthmaThreatCalculatorUseCase { // MARK: - Asthma Severity Calculation - private func calculateAsthmaSeverity(biosignalSamples: [HKQuantitySample], environmentalData: (EnviromentalData.AirQualityData?, EnviromentalData.PollenForecastData?), weatherData: WeatherKitData.WeatherData) { - let userID = 1 // Example userID, replace with actual user ID + private func calculateAsthmaSeverity(userID: Int, biosignalSamples: [HKQuantitySample], environmentalData: (EnviromentalData.AirQualityData?, EnviromentalData.PollenForecastData?), weatherData: WeatherKitData.WeatherData) { databaseManager.fetchAsthmaTriggers(forUserID: userID) { triggerGrades in let heartRateSeverity = HealthDataAnalyzer.calculateHeartRateSeverity(samples: biosignalSamples) let respiratoryRateSeverity = HealthDataAnalyzer.calculateRespiratoryRateSeverity(samples: biosignalSamples) let oxygenSaturationSeverity = HealthDataAnalyzer.calculateOxygenSaturationSeverity(samples: biosignalSamples) - var airQualitySeverity = 0.0 - if let airQualityData = environmentalData.0 { - airQualitySeverity = self.calculateAQISeverity(aqiLevel: airQualityData.universalAQI) - } - + let airQualitySeverity = self.calculateAQISeverity(aqiLevel: environmentalData.0?.universalAQI) let pollenSeverity = self.calculatePollenSeverity(pollenForecastData: environmentalData.1) let humiditySeverity = self.weatherKitData.calculateHumiditySeverity(humidity: weatherData.humidity) let cloudCoverSeverity = self.weatherKitData.calculateCloudCoverSeverity(cloudCover: weatherData.cloudCover) let temperatureSeverity = self.weatherKitData.calculateTemperatureSeverity(temperature: weatherData.temperature) - let weightedSeverity = self.calculateWeightedSeverity( - heartRateSeverity: heartRateSeverity, - respiratoryRateSeverity: respiratoryRateSeverity, - oxygenSaturationSeverity: oxygenSaturationSeverity, - airQualitySeverity: airQualitySeverity, - pollenSeverity: pollenSeverity, - humiditySeverity: humiditySeverity, - cloudCoverSeverity: cloudCoverSeverity, - temperatureSeverity: temperatureSeverity, - triggerGrades: triggerGrades - ) + self.weightedHeartRateSeverity = heartRateSeverity * Double(triggerGrades[0]) + self.weightedRespiratoryRateSeverity = respiratoryRateSeverity * Double(triggerGrades[1]) + self.weightedOxygenSaturationSeverity = oxygenSaturationSeverity * Double(triggerGrades[2]) + self.weightedAirQualitySeverity = airQualitySeverity * Double(triggerGrades[3]) + self.weightedPollenSeverity = pollenSeverity * Double(triggerGrades[4]) + self.weightedHumiditySeverity = humiditySeverity * Double(triggerGrades[5]) + self.weightedCloudCoverSeverity = cloudCoverSeverity * Double(triggerGrades[6]) + self.weightedTemperatureSeverity = temperatureSeverity * Double(triggerGrades[7]) - print("Asthma Threat: \(Int(weightedSeverity * 100))%") + let biosignalWeightsTotal = Double(triggerGrades[0] + triggerGrades[1] + triggerGrades[2]) + let environmentalWeightsTotal = Double(triggerGrades[3] + triggerGrades[4] + triggerGrades[5] + triggerGrades[6] + triggerGrades[7]) + let totalWeights = biosignalWeightsTotal + environmentalWeightsTotal + + self.weightedBioSignalRisk = ( + self.weightedHeartRateSeverity + + self.weightedRespiratoryRateSeverity + + self.weightedOxygenSaturationSeverity + ) / biosignalWeightsTotal + + self.weightedEnvironmentalRisk = ( + self.weightedAirQualitySeverity + + self.weightedPollenSeverity + + self.weightedHumiditySeverity + + self.weightedCloudCoverSeverity + + self.weightedTemperatureSeverity + ) / environmentalWeightsTotal + + self.totalWeightedSeverity = ( + self.weightedHeartRateSeverity + + self.weightedRespiratoryRateSeverity + + self.weightedOxygenSaturationSeverity + + self.weightedAirQualitySeverity + + self.weightedPollenSeverity + + self.weightedHumiditySeverity + + self.weightedCloudCoverSeverity + + self.weightedTemperatureSeverity + ) / totalWeights + + print("Weighted Environmental Risk: \(self.weightedEnvironmentalRisk)") + print("Weighted BioSignal Risk: \(self.weightedBioSignalRisk)") + print("Total Weighted Severity: \(self.totalWeightedSeverity)") } } @@ -184,31 +248,8 @@ class AsthmaThreatCalculatorUseCase { let maxSeverity = pollenTypes.map { categorySeverityMap[$0.indexInfo.category] ?? 0.0 }.max() ?? 0.0 return maxSeverity } - - func calculateWeightedSeverity( - heartRateSeverity: Double, - respiratoryRateSeverity: Double, - oxygenSaturationSeverity: Double, - airQualitySeverity: Double, - pollenSeverity: Double, - humiditySeverity: Double, - cloudCoverSeverity: Double, - temperatureSeverity: Double, - triggerGrades: [Int] - ) -> Double { - let totalGrade = Double(triggerGrades.reduce(0, +)) - - let weightedSeverity = ( - (heartRateSeverity * Double(triggerGrades[0])) + - (respiratoryRateSeverity * Double(triggerGrades[1])) + - (oxygenSaturationSeverity * Double(triggerGrades[2])) + - (airQualitySeverity * Double(triggerGrades[3])) + - (pollenSeverity * Double(triggerGrades[4])) + - (humiditySeverity * Double(triggerGrades[5])) + - (cloudCoverSeverity * Double(triggerGrades[6])) + - (temperatureSeverity * Double(triggerGrades[7])) - ) / totalGrade - - return weightedSeverity - } + + private func getPatientToken() -> Int? { + return SessionManager.shared.getCurrentToken() + } } diff --git a/Asthmaguard/ContentView.swift b/Asthmaguard/ContentView.swift index 5f5e099..cfb0cba 100644 --- a/Asthmaguard/ContentView.swift +++ b/Asthmaguard/ContentView.swift @@ -10,7 +10,7 @@ import SwiftUI @available(iOS 17.0, *) struct ContentView: View { var body: some View { - BreathingExerciseScreen() + RegisterScreen() } } diff --git a/Asthmaguard/Data/Models/AsthmaThreatModel.swift b/Asthmaguard/Data/Models/AsthmaThreatModel.swift new file mode 100644 index 0000000..2511aff --- /dev/null +++ b/Asthmaguard/Data/Models/AsthmaThreatModel.swift @@ -0,0 +1,14 @@ +// +// AsthmaThreatModel.swift +// Asthmaguard +// +// Created by Sadeel Muwahed on 27/05/2024. +// + +import Foundation + +struct AsthmaThreat: Identifiable { + let id = UUID() + let title: String + let risks: Double +} diff --git a/Asthmaguard/Data/Models/AsthmaTriggerModel.swift b/Asthmaguard/Data/Models/AsthmaTriggerModel.swift new file mode 100644 index 0000000..ff487bd --- /dev/null +++ b/Asthmaguard/Data/Models/AsthmaTriggerModel.swift @@ -0,0 +1,14 @@ +// +// AsthmaTrigger.swift +// Asthmaguard +// +// Created by Sadeel Muwahed on 26/05/2024. +// + +import Foundation + +struct AsthmaTrigger { + let triggerID: Int + let patientID: Int + let grade: Int +} diff --git a/Asthmaguard/DataSource/Endpoints/Database/DatabaseSetUp.swift b/Asthmaguard/DataSource/Endpoints/Database/DatabaseSetUp.swift index cbefa37..d5c5bf7 100644 --- a/Asthmaguard/DataSource/Endpoints/Database/DatabaseSetUp.swift +++ b/Asthmaguard/DataSource/Endpoints/Database/DatabaseSetUp.swift @@ -68,14 +68,21 @@ class DatabaseManager { static let shared = DatabaseManager() var database: SQLiteDatabase + init() { let dbPath = try! FileManager.default .url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) - .appendingPathComponent("YourDatabaseName.sqlite").path + .appendingPathComponent("AsthmaGuardDatabase.sqlite").path + // Delete the existing database file + if FileManager.default.fileExists(atPath: dbPath) { + try? FileManager.default.removeItem(atPath: dbPath) + } + database = try! SQLiteDatabase.open(path: dbPath) try! createTables() } + //MARK: CREATE TABLES @@ -184,56 +191,79 @@ class DatabaseManager { } //MARK: User Add and Update - func addUser(username: String, password: String, email: String, token: Int?) -> Int? { + func addUser(username: String, password: String, email: String, token: Int) -> Bool { let currentDate = Date() let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd" let creationDate = dateFormatter.string(from: currentDate) - let tokenValue = token != nil ? "\(token!)" : "NULL" let userSQL = """ INSERT INTO Users (Username, Password, Email, CreationDate, Token) - VALUES ('\(username)', '\(password)', '\(email)', '\(creationDate)', \(tokenValue)); + VALUES ('\(username)', '\(password)', '\(email)', '\(creationDate)', \(token)); """ do { - let userID = try database.executeInsert(sql: userSQL) - print("User added successfully with UserID = \(userID).") - return userID + let _ = try database.executeInsert(sql: userSQL) + print("User added successfully with Token = \(token).") + return true } catch { print("Error adding user: \(error)") - return nil + return false } } + func validateUser(email: String, password: String) -> (username: String, token: Int)? { + let querySQL = "SELECT Username, Token FROM Users WHERE Email = ? AND Password = ?;" + var queryStatement: OpaquePointer? = nil + var user: (username: String, token: Int)? = nil + + if sqlite3_prepare_v2(database.dbPointer, querySQL, -1, &queryStatement, nil) == SQLITE_OK { + sqlite3_bind_text(queryStatement, 1, (email as NSString).utf8String, -1, nil) + sqlite3_bind_text(queryStatement, 2, (password as NSString).utf8String, -1, nil) + + if sqlite3_step(queryStatement) == SQLITE_ROW { + let username = String(cString: sqlite3_column_text(queryStatement, 0)) + let token = Int(sqlite3_column_int(queryStatement, 1)) + user = (username, token) + } + + sqlite3_finalize(queryStatement) + } else { + let errmsg = String(cString: sqlite3_errmsg(database.dbPointer)) + print("Error preparing select statement: \(errmsg)") + } + + return user + } + func updateUser(userID: Int, newUsername: String, newPassword: String, newEmail: String, newToken: Int?) { - let updateSQL = "UPDATE Users SET Username = ?, Password = ?, Email = ?, Token = ? WHERE UserID = ?;" - - var updateStatement: OpaquePointer? = nil - if sqlite3_prepare_v2(database.dbPointer, updateSQL, -1, &updateStatement, nil) == SQLITE_OK { - sqlite3_bind_text(updateStatement, 1, (newUsername as NSString).utf8String, -1, nil) - sqlite3_bind_text(updateStatement, 2, (newPassword as NSString).utf8String, -1, nil) - sqlite3_bind_text(updateStatement, 3, (newEmail as NSString).utf8String, -1, nil) - if let token = newToken { - sqlite3_bind_int(updateStatement, 4, Int32(token)) - } else { - sqlite3_bind_null(updateStatement, 4) - } - sqlite3_bind_int(updateStatement, 5, Int32(userID)) - - if sqlite3_step(updateStatement) == SQLITE_DONE { - print("Successfully updated user.") - } else { - let errmsg = String(cString: sqlite3_errmsg(database.dbPointer)) - print("Failed to update user: \(errmsg)") - } - - // Finalize the statement to release resources - sqlite3_finalize(updateStatement) - } else { - let errmsg = String(cString: sqlite3_errmsg(database.dbPointer)) - print("Error preparing update statement for Users: \(errmsg)") - } - } + let updateSQL = "UPDATE Users SET Username = ?, Password = ?, Email = ?, Token = ? WHERE UserID = ?;" + + var updateStatement: OpaquePointer? = nil + if sqlite3_prepare_v2(database.dbPointer, updateSQL, -1, &updateStatement, nil) == SQLITE_OK { + sqlite3_bind_text(updateStatement, 1, (newUsername as NSString).utf8String, -1, nil) + sqlite3_bind_text(updateStatement, 2, (newPassword as NSString).utf8String, -1, nil) + sqlite3_bind_text(updateStatement, 3, (newEmail as NSString).utf8String, -1, nil) + if let token = newToken { + sqlite3_bind_int(updateStatement, 4, Int32(token)) + } else { + sqlite3_bind_null(updateStatement, 4) + } + sqlite3_bind_int(updateStatement, 5, Int32(userID)) + + if sqlite3_step(updateStatement) == SQLITE_DONE { + print("Successfully updated user.") + } else { + let errmsg = String(cString: sqlite3_errmsg(database.dbPointer)) + print("Failed to update user: \(errmsg)") + } + + // Finalize the statement to release resources + sqlite3_finalize(updateStatement) + } else { + let errmsg = String(cString: sqlite3_errmsg(database.dbPointer)) + print("Error preparing update statement for Users: \(errmsg)") + } + } //MARK: Patient Add and Update @@ -323,12 +353,14 @@ extension DatabaseManager { func insertInitialTriggers(db: OpaquePointer?) { let triggers = [ + (0, "heart rate"), (1, "repository rate"), (2, "blood oxygen"), - (3, "heart rate"), - (4, "fine particals"), - (5, "pollen"), - (6, "pollution") + (3, "air quality"), + (4, "pollen"), + (5, "humidity"), + (6, "cloudover"), + (7,"temperature") ] let insertStatementString = "INSERT INTO Triggers (TriggerID, TriggerName) VALUES (?, ?);" var insertStatement: OpaquePointer? @@ -541,26 +573,49 @@ extension DatabaseManager { // MARK: - Fetch Users func fetchUsers() { - let querySQL = "SELECT UserID, Username, Password, Email, CreationDate, Token FROM Users;" - executeFetch(querySQL: querySQL, handleRow: { (statement) in - let userID = sqlite3_column_int(statement, 0) - guard let usernameCString = sqlite3_column_text(statement, 1), - let passwordCString = sqlite3_column_text(statement, 2), - let emailCString = sqlite3_column_text(statement, 3), - let creationDateCString = sqlite3_column_text(statement, 4) else { - return - } - let token = sqlite3_column_int(statement, 5) - - let username = String(cString: usernameCString) - let password = String(cString: passwordCString) - let email = String(cString: emailCString) - let creationDate = String(cString: creationDateCString) - - print("User ID: \(userID), Username: \(username), Password: \(password), Email: \(email), Creation Date: \(creationDate), Token: \(token)") - }) - } + let querySQL = "SELECT UserID, Username, Password, Email, CreationDate, Token FROM Users;" + executeFetch(querySQL: querySQL, handleRow: { (statement) in + let userID = sqlite3_column_int(statement, 0) + guard let usernameCString = sqlite3_column_text(statement, 1), + let passwordCString = sqlite3_column_text(statement, 2), + let emailCString = sqlite3_column_text(statement, 3), + let creationDateCString = sqlite3_column_text(statement, 4) else { + return + } + let token = sqlite3_column_int(statement, 5) + + let username = String(cString: usernameCString) + let password = String(cString: passwordCString) + let email = String(cString: emailCString) + let creationDate = String(cString: creationDateCString) + + print("User ID: \(userID), Username: \(username), Password: \(password), Email: \(email), Creation Date: \(creationDate), Token: \(token)") + }) + } + // MARK: - Fetch User ID by Username + + func fetchUserID(byToken token: Int, completion: @escaping (Int?) -> Void) { + let querySQL = "SELECT UserID FROM Users WHERE Token = ?;" + var queryStatement: OpaquePointer? = nil + var userID: Int? + + if sqlite3_prepare_v2(database.dbPointer, querySQL, -1, &queryStatement, nil) == SQLITE_OK { + sqlite3_bind_int(queryStatement, 1, Int32(token)) + + if sqlite3_step(queryStatement) == SQLITE_ROW { + userID = Int(sqlite3_column_int(queryStatement, 0)) + } + + sqlite3_finalize(queryStatement) + } else { + let errmsg = String(cString: sqlite3_errmsg(database.dbPointer)) + print("Error preparing select statement: \(errmsg)") + } + + completion(userID) + } + // MARK: - Fetch Patients func fetchPatient(userID: Int) { diff --git a/Asthmaguard/Presentation/View/AnalyticsView.swift b/Asthmaguard/Presentation/View/AnalyticsView.swift index c29727a..434f7a0 100644 --- a/Asthmaguard/Presentation/View/AnalyticsView.swift +++ b/Asthmaguard/Presentation/View/AnalyticsView.swift @@ -10,115 +10,171 @@ import SwiftUI import Charts struct AnalyticsView: View { - - let asthmaThreats: [AsthmaThreat] = [ - AsthmaThreat(title: "Biosignals", risks: 0.3), - AsthmaThreat(title: "Environmental", risks: 0.1), - ] - - @State var enviromental: [Enviromental] = [ - .init(title: "Pollen", severity: 0.2), - .init(title: "Air Quality", severity: 0.4), - .init(title: "Cloudover", severity: 0.05), - .init(title:"Humidity", severity: 0.15), - .init(title: "Temperature", severity: 0.1) - ] - - @State var biosignals: [BioSignal] = [ - .init(title: "Respitory Rate", severity: 0.3), - .init(title: "Heart Rate", severity: 0.3), - .init(title: "SpO2", severity: 0.1), - ] - + @State private var heartRateSeverity: Double = 0.0 + @State private var respiratoryRateSeverity: Double = 0.0 + @State private var oxygenSaturationSeverity: Double = 0.0 + @State private var airQualitySeverity: Double = 0.0 + @State private var pollenSeverity: Double = 0.0 + @State private var humiditySeverity: Double = 0.0 + @State private var cloudCoverSeverity: Double = 0.0 + @State private var temperatureSeverity: Double = 0.0 + + private let asthmaThreatCalculatorUseCase = AsthmaThreatCalculatorUseCase() + + func updateSeverities() { + DispatchQueue.main.async { + self.heartRateSeverity = asthmaThreatCalculatorUseCase.weightedHeartRateSeverity + self.respiratoryRateSeverity = asthmaThreatCalculatorUseCase.weightedRespiratoryRateSeverity + self.oxygenSaturationSeverity = asthmaThreatCalculatorUseCase.weightedOxygenSaturationSeverity + self.airQualitySeverity = asthmaThreatCalculatorUseCase.weightedAirQualitySeverity + self.pollenSeverity = asthmaThreatCalculatorUseCase.weightedPollenSeverity + self.humiditySeverity = asthmaThreatCalculatorUseCase.weightedHumiditySeverity + self.cloudCoverSeverity = asthmaThreatCalculatorUseCase.weightedCloudCoverSeverity + self.temperatureSeverity = asthmaThreatCalculatorUseCase.weightedTemperatureSeverity + } + } + var body: some View { ScrollView { Text("Analytics") .font(Font.custom("Poppins-Bold", size: 18)) .padding(.all, 5) - - VStack(spacing:5){ + + VStack(spacing: 5) { Text("Asthma Threat Breakdown") .font(Font.custom("Poppins-Regular", size: 22)) .padding(.all, 5) - - VStack(spacing:5){ - + + VStack(spacing: 5) { let enviromentalChartColors: [Color] = [ .pink, .cyan, .green, .blue, .yellow ] - + let biosignalChartColors: [Color] = [ .pink, .blue, .green ] - - VStack(spacing:5){ - - VStack(spacing:5){ - Divider() - Text("๐Ÿ“ˆ Biosignal Data Breakdown") - .font(Font.custom("Poppins-Bold", size: 18)) - .padding() - Chart(biosignals) { biosignal in - SectorMark( - angle: .value( - Text(biosignal.title), - biosignal.severity - ), - innerRadius: .ratio(0.6), - angularInset: 0.8 - ) - .cornerRadius(4) - .foregroundStyle(by: .value("Threats", biosignal.title)) - }.frame(width: 300, height: 175) - .chartForegroundStyleScale(domain: .automatic, range: biosignalChartColors) - - Text("The biosignal data and vital signs are increasing the asthma threat by 30%.") - .font(Font.custom("Poppins-Regular", size: 14)) - .padding() - .multilineTextAlignment(.leading) + + VStack(spacing: 5) { + Divider() + Text("๐Ÿ“ˆ Biosignal Data Breakdown") + .font(Font.custom("Poppins-Bold", size: 18)) + .padding() + + VStack(alignment: .leading) { + Text("Heart Rate: \(heartRateSeverity * 100, specifier: "%.1f")%") + Text("Respiratory Rate: \(respiratoryRateSeverity * 100, specifier: "%.1f")%") + Text("SpO2: \(oxygenSaturationSeverity * 100, specifier: "%.1f")%") } - - Divider().padding(.all, 10) - - VStack(spacing:5){ - Text("๐Ÿ“Š Enviromental Data Breakdown") - .font(Font.custom("Poppins-Bold", size: 18)) - .padding() - Chart(enviromental) { enviromental in - SectorMark( - angle: .value( - Text(enviromental.title), - enviromental.severity - ), - innerRadius: .ratio(0.6), - angularInset: 0.8 - ) - .cornerRadius(4) - .foregroundStyle(by: .value("Threats", enviromental.title)) - }.frame(width: 300, height: 175) - .chartForegroundStyleScale(domain: .automatic, range: enviromentalChartColors) - - Text("The enviromental data is increasing the asthma threat by a total of 10%.") - .font(Font.custom("Poppins-Regular", size: 14)) - .padding() - .multilineTextAlignment(.leading) - + .padding() + + Text("The biosignal data and vital signs are increasing the asthma threat by \(heartRateSeverity + respiratoryRateSeverity + oxygenSaturationSeverity, specifier: "%.1f")%.") + .font(Font.custom("Poppins-Regular", size: 14)) + .padding() + .multilineTextAlignment(.leading) + + Chart { + SectorMark( + angle: .value("Heart Rate", heartRateSeverity), + innerRadius: .ratio(0.6), + angularInset: 0.8 + ) + .cornerRadius(4) + .foregroundStyle(by: .value("Threats", "Heart Rate")) + + SectorMark( + angle: .value("Respiratory Rate", respiratoryRateSeverity), + innerRadius: .ratio(0.6), + angularInset: 0.8 + ) + .cornerRadius(4) + .foregroundStyle(by: .value("Threats", "Respiratory Rate")) + + SectorMark( + angle: .value("SpO2", oxygenSaturationSeverity), + innerRadius: .ratio(0.6), + angularInset: 0.8 + ) + .cornerRadius(4) + .foregroundStyle(by: .value("Threats", "SpO2")) } - Divider() - Spacer() + .frame(width: 300, height: 175) + .chartForegroundStyleScale(domain: ["Heart Rate", "Respiratory Rate", "SpO2"], range: biosignalChartColors) } + + Divider().padding(.all, 10) + + VStack(spacing: 5) { + Text("๐Ÿ“Š Environmental Data Breakdown") + .font(Font.custom("Poppins-Bold", size: 18)) + .padding() + + VStack(alignment: .leading) { + Text("Pollen: \(pollenSeverity * 100, specifier: "%.1f")%") + Text("Air Quality: \(airQualitySeverity * 100, specifier: "%.1f")%") + Text("Humidity: \(humiditySeverity * 100, specifier: "%.1f")%") + Text("Cloud Cover: \(cloudCoverSeverity * 100, specifier: "%.1f")%") + Text("Temperature: \(temperatureSeverity * 100, specifier: "%.1f")%") + } + .padding() + + Text("The environmental data is increasing the asthma threat by a total of \(pollenSeverity + airQualitySeverity + humiditySeverity + cloudCoverSeverity + temperatureSeverity, specifier: "%.1f")%.") + .font(Font.custom("Poppins-Regular", size: 14)) + .padding() + .multilineTextAlignment(.leading) + + Chart { + SectorMark( + angle: .value("Pollen", pollenSeverity), + innerRadius: .ratio(0.6), + angularInset: 0.8 + ) + .cornerRadius(4) + .foregroundStyle(by: .value("Threats", "Pollen")) + + SectorMark( + angle: .value("Air Quality", airQualitySeverity), + innerRadius: .ratio(0.6), + angularInset: 0.8 + ) + .cornerRadius(4) + .foregroundStyle(by: .value("Threats", "Air Quality")) + + SectorMark( + angle: .value("Humidity", humiditySeverity), + innerRadius: .ratio(0.6), + angularInset: 0.8 + ) + .cornerRadius(4) + .foregroundStyle(by: .value("Threats", "Humidity")) + + SectorMark( + angle: .value("Cloud Cover", cloudCoverSeverity), + innerRadius: .ratio(0.6), + angularInset: 0.8 + ) + .cornerRadius(4) + .foregroundStyle(by: .value("Threats", "Cloud Cover")) + + SectorMark( + angle: .value("Temperature", temperatureSeverity), + innerRadius: .ratio(0.6), + angularInset: 0.8 + ) + .cornerRadius(4) + .foregroundStyle(by: .value("Threats", "Temperature")) + } + .frame(width: 300, height: 175) + .chartForegroundStyleScale(domain: ["Pollen", "Air Quality", "Humidity", "Cloud Cover", "Temperature"], range: enviromentalChartColors) + } + + Divider() + Spacer() } - - Spacer() - - } + Spacer() + } + .onAppear { + updateSeverities() } - } -} - -struct AnalyticsView_Previews: PreviewProvider { - static var previews: some View { - AnalyticsView() } } diff --git a/Asthmaguard/Presentation/View/DashboardView.swift b/Asthmaguard/Presentation/View/DashboardView.swift index 57cf20b..d8c942c 100644 --- a/Asthmaguard/Presentation/View/DashboardView.swift +++ b/Asthmaguard/Presentation/View/DashboardView.swift @@ -10,66 +10,58 @@ import SwiftUI import Charts import CoreLocation -struct AsthmaThreat: Identifiable { - let id = UUID() - let title: String - let risks: Double -} +@available(iOS 17.0, *) +struct AsthmaThreatChart: View { + @State private var totalWeightedSeverity: Double = 0.0 + @State private var biosignalRisk: Double = 0.0 + @State private var environmentalRisk: Double = 0.0 + @State private var normal: Double = 0.0 -struct Enviromental: Identifiable{ - var id = UUID() - let title: String - let severity: Double -} -struct BioSignal: Identifiable{ - var id = UUID() - let title: String - let severity: Double -} + @State var asthmathreat: [AsthmaThreat] = [ + .init(title: "Biosignals", risks: 0.0), + .init(title: "Enviromental", risks: 0.0), + .init(title: "Normal", risks: 0.0) + ] + private let asthmaThreatCalculatorUseCase = AsthmaThreatCalculatorUseCase() -func colorForRisk(_ title: String) -> Color { - switch title { - case "Biosignals": - return .pink - case "Enviromental": - return .pink - case "Normal": - return .blue - default: - return .blue + func updateAsthmaThreat() { + asthmaThreatCalculatorUseCase.fetchDataAndCalculateAsthmaSeverity() + DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { + // Use a delay to allow for data fetching; adjust timing as necessary + self.biosignalRisk = asthmaThreatCalculatorUseCase.weightedBioSignalRisk + self.environmentalRisk = asthmaThreatCalculatorUseCase.weightedEnvironmentalRisk + self.totalWeightedSeverity = asthmaThreatCalculatorUseCase.totalWeightedSeverity + self.normal = 1 - self.totalWeightedSeverity + + self.updateAsthmaThreatArray() + } + } + + func updateAsthmaThreatArray() { + self.asthmathreat = [ + .init(title: "Biosignals", risks: self.biosignalRisk), + .init(title: "Enviromental", risks: self.environmentalRisk), + .init(title: "Normal", risks: self.normal) + ] } -} -@available(iOS 17.0, *) -struct AsthmaThreatChart: View { - @State var asthmathreat: [AsthmaThreat] = [ - .init(title: "Biosignals", risks: 0.3), - .init(title: "Enviromental", risks: 0.1), - .init(title: "Normal", risks: 0.6) - ] - - @State private var showDetailsView = false - + var body: some View { - - ScrollView(showsIndicators:false){ - VStack(spacing:20){ + ScrollView(showsIndicators: false) { + VStack(spacing: 20) { Text("Dashboard") .font(Font.custom("Poppins-Bold", size: 18)) .padding(.all) - + let chartColors: [Color] = [ .pink.opacity(0.5), .pink, .blue ] - - - let asthmaThreatRisks:Double = 0.4 - - Text("Asthma Threat: \(asthmaThreatRisks * 100, specifier: "%.1f")%") + + Text("Asthma Threat: \(totalWeightedSeverity * 100, specifier: "%.1f")%") .font(Font.custom("Poppins-Bold", size: 26)) - + Chart(asthmathreat) { asthmathreat in SectorMark( angle: .value( @@ -82,18 +74,19 @@ struct AsthmaThreatChart: View { .cornerRadius(4) .foregroundStyle(by: .value("Threats", asthmathreat.title)) }.frame(width: 300, height: 250) - .chartForegroundStyleScale(domain: .automatic, range: chartColors) - - Spacer() - VStack(spacing:10){ + .chartForegroundStyleScale(domain: .automatic, range: chartColors) + + Spacer() + VStack(spacing: 10) { CustomBioData(bioSignal: "Respiratory Rate", time: "11:55 AM", data: "19 breathes/min") - CustomBioData(bioSignal: "Heart Rate", time: "12:01 PM", data: "96 BPM") - CustomBioData(bioSignal: "Blood Oxygen", time: "12:03 PM", data: "98.5%") } Spacer() } + .onAppear() { + updateAsthmaThreat() + } } } } @@ -103,14 +96,25 @@ struct AsthmaThreatChart: View { struct DashboardView: View { @State private var selection = 0 + private let locationManager = LocationManager.shared + private let asthmaThreatCalculatorUseCase = AsthmaThreatCalculatorUseCase() var body: some View { - TabView(selection:$selection) { NavigationView { AsthmaThreatChart() .navigationTitle("") .navigationBarBackButtonHidden(false) + .onAppear { + locationManager.requestLocation() + BioSignalData.requestHealthDataAccessIfNeeded { success in + if success { + asthmaThreatCalculatorUseCase.startMonitoring() + } else { + print("Health data access denied.") + } + } + } }.tabItem { Label("Dashboard", systemImage: "house") } diff --git a/Asthmaguard/Presentation/View/LoginScreen.swift b/Asthmaguard/Presentation/View/LoginScreen.swift index b75122d..bed003f 100644 --- a/Asthmaguard/Presentation/View/LoginScreen.swift +++ b/Asthmaguard/Presentation/View/LoginScreen.swift @@ -14,15 +14,12 @@ struct LoginScreen: View { var body: some View { if loginViewModel.isLogin { - if loginViewModel.shouldNavigateToCompanionDashboard{ + if loginViewModel.shouldNavigateToCompanionDashboard { CompanionDashboardView() - } - else{ + } else { DashboardView() } - } - - else{ + } else { VStack { Spacer() Text("Asthma") @@ -42,7 +39,7 @@ struct LoginScreen: View { CustomTextField(systemName: "lock", placeholder: "Password", text: $loginViewModel.password) - Button(action: {loginViewModel.login()}) { + Button(action: { loginViewModel.login() }) { Text("Login") .font(Font.custom("Poppins-Regular", size: 14).weight(.bold)) .foregroundColor(.white) @@ -55,9 +52,7 @@ struct LoginScreen: View { .shadow(color: Color(red: 0.58, green: 0.68, blue: 1, opacity: 0.30), radius: 22, y: 10) } - - - Button(action: {loginViewModel.companion()}) { + Button(action: { loginViewModel.companion() }) { Text("Companionโ€™s portal") .font(Font.custom("Poppins-Regular", size: 14).weight(.bold)) .foregroundColor(.white) @@ -70,18 +65,17 @@ struct LoginScreen: View { .shadow(color: Color(red: 0.58, green: 0.68, blue: 1, opacity: 0.30), radius: 22, y: 10) } - HStack(spacing: 3){ + HStack(spacing: 3) { Text("Do not have an account?") .font(Font.custom("Poppins", size: 14)) .lineSpacing(21) .foregroundColor(Color(red: 0.12, green: 0.09, blue: 0.09)) - Button(action:{loginViewModel.register()}){ + Button(action: { loginViewModel.register() }) { Text("Get Started!") .font(Font.custom("Poppins", size: 14)) .foregroundColor(Color(red: 0.57, green: 0.64, blue: 0.99)) } } - } .padding(.horizontal, 32) .padding(.top, 50) @@ -91,11 +85,4 @@ struct LoginScreen: View { .background(Color.white) } } - -} - -struct LoginScreen_Previews: PreviewProvider { - static var previews: some View { - LoginScreen() - } } diff --git a/Asthmaguard/Presentation/View/RegisterScreen.swift b/Asthmaguard/Presentation/View/RegisterScreen.swift index c35e0de..a6287ab 100644 --- a/Asthmaguard/Presentation/View/RegisterScreen.swift +++ b/Asthmaguard/Presentation/View/RegisterScreen.swift @@ -16,8 +16,7 @@ struct RegisterScreen: View { var body: some View { if registerViewModel.isRegistered { LoginScreen() - } - else{ + } else { Spacer() VStack(spacing: 20) { Text("Asthma") @@ -27,7 +26,7 @@ struct RegisterScreen: View { .font(Font.custom("Poppins-Regular", size: 32).weight(.bold)) .foregroundColor(Color(red: 0.57, green: 0.64, blue: 0.99)) Spacer() - VStack(spacing:5){ + VStack(spacing: 5) { Text("Hey there,") .font(Font.custom("Poppins-Regular", size: 16)) .lineSpacing(24) @@ -41,7 +40,7 @@ struct RegisterScreen: View { Spacer() - VStack(spacing:2){ + VStack(spacing: 2) { CustomTextField(systemName: "person", placeholder: "First Name", text: $registerViewModel.firstName).padding(10) CustomTextField(systemName: "person", placeholder: "Last Name", text: $registerViewModel.lastName).padding(10) @@ -64,7 +63,7 @@ struct RegisterScreen: View { } - VStack(spacing:10) { + VStack(spacing: 10) { Button(action: registerViewModel.register) { Text("Register") .font(Font.custom("Poppins-Regular", size: 14).weight(.bold)) @@ -84,15 +83,15 @@ struct RegisterScreen: View { } - HStack(spacing: 3){ + HStack(spacing: 3) { Text("Already have an account?") .font(Font.custom("Poppins", size: 14)) .lineSpacing(21) .foregroundColor(Color(red: 0.12, green: 0.09, blue: 0.09)) - Button(action:{registerViewModel.login()}){ + Button(action: { registerViewModel.login() }) { Text("Login!") - .font(Font.custom("Poppins", size: 14)) - .foregroundColor(Color(red: 0.57, green: 0.64, blue: 0.99)) + .font(Font.custom("Poppins", size: 14)) + .foregroundColor(Color(red: 0.57, green: 0.64, blue: 0.99)) } } } @@ -102,8 +101,6 @@ struct RegisterScreen: View { Spacer() } } - - } @available(iOS 17.0, *) diff --git a/Asthmaguard/Presentation/ViewModels/LoginViewModel.swift b/Asthmaguard/Presentation/ViewModels/LoginViewModel.swift index 33bc21f..8f40020 100644 --- a/Asthmaguard/Presentation/ViewModels/LoginViewModel.swift +++ b/Asthmaguard/Presentation/ViewModels/LoginViewModel.swift @@ -7,27 +7,36 @@ import Foundation -class LoginViewModel:ObservableObject{ - @Published var email:String = "" - @Published var password:String = "" +class LoginViewModel: ObservableObject { + @Published var email: String = "" + @Published var password: String = "" @Published var isLogin: Bool = false @Published var shouldNavigateToCompanionDashboard: Bool = false - - func login(){ - DatabaseManager.shared.fetchUsers() - isLogin = true + func login() { + if let user = DatabaseManager.shared.validateUser(email: email, password: password) { + SessionManager.shared.login(token: user.token) + isLogin = true + } else { + print("Invalid email or password") + } } - - func loginWithApple(){ - print("Login with apple") + + func loginWithApple() { + print("Login with Apple") } - - func companion(){ + + func companion() { isLogin = true shouldNavigateToCompanionDashboard = true } - func register(){ + + func register() { + // Navigation logic to register screen } } + + + + diff --git a/Asthmaguard/Presentation/ViewModels/RegisterViewModel.swift b/Asthmaguard/Presentation/ViewModels/RegisterViewModel.swift index b5d3d71..fb2252f 100644 --- a/Asthmaguard/Presentation/ViewModels/RegisterViewModel.swift +++ b/Asthmaguard/Presentation/ViewModels/RegisterViewModel.swift @@ -14,19 +14,27 @@ class RegisterViewModel: ObservableObject { @Published var password: String = "" @Published var isRegistered: Bool = false - func register() { - DatabaseManager.shared.addUser(username: firstName+lastName, password: password, email: email, token: 123) - isRegistered = true + let username = firstName + lastName + let token = generateToken() + if DatabaseManager.shared.addUser(username: username, password: password, email: email, token: token) { + SessionManager.shared.login(token: token) + isRegistered = true + } else { + print("Failed to register user") + } + } - } - func registerWithApple() { print("Register with Apple") } - - func login(){ + + func login() { + // Navigation logic to login screen } -} + private func generateToken() -> Int { + return Int.random(in: 100000...999999) + } +}