From 197a971a7c40b5c43beab57583ace742efa91307 Mon Sep 17 00:00:00 2001 From: Chandram-Dutta Date: Fri, 26 Apr 2024 09:59:07 +0530 Subject: [PATCH] feat: better logging, updated dependencies --- VITTY/ContentView.swift | 2 +- VITTY/VITTY.xcodeproj/project.pbxproj | 62 ++--- .../xcshareddata/swiftpm/Package.resolved | 67 ++--- VITTY/VITTY/Auth/Service/AuthAPIService.swift | 6 +- .../VITTY/Auth/ViewModels/AuthViewModel.swift | 167 ++++++++----- .../AddFriends/View/AddFriendsView.swift | 2 +- .../ViewModel/FriendRequestViewModel.swift | 12 +- .../Views/Components/FriendReqCard.swift | 66 ++--- .../Views/FriendRequestView.swift | 2 +- .../Circle/Search/Views/SearchView.swift | 17 +- .../ViewModel/SuggestedFriendsViewModel.swift | 10 +- .../Views/Components/AddFriendCard.swift | 15 +- .../Views/SuggestedFriendsView.swift | 2 +- VITTY/VITTY/Circle/View/CommunityPage.swift | 10 +- .../View/Components/CommunityPageHeader.swift | 6 +- .../ViewModel/CommunityPageViewModel.swift | 10 +- .../Instruction/Views/InstructionView.swift | 2 +- VITTY/VITTY/TimeTable/Models/TimeTable.swift | 21 +- .../Service/TimeTableAPIService.swift | 4 +- .../ViewModel/TimeTableViewModel.swift | 20 +- .../TimeTable/Views/LectureDetailView.swift | 3 + .../VITTY/TimeTable/Views/TimeTableView.swift | 228 ++++++++++-------- VITTY/VITTY/Username/Views/UsernameView.swift | 2 +- .../Utilities/Constants/StringConstants.swift | 20 +- VITTY/VITTYApp.swift | 35 ++- VITTY/vittywidget/AppIntent.swift | 12 +- VITTY/vittywidget/vittywidget.swift | 118 +++++---- VITTY/vittywidget/vittywidgetBundle.swift | 10 +- .../vittywidget/vittywidgetLiveActivity.swift | 106 ++++---- 29 files changed, 578 insertions(+), 459 deletions(-) diff --git a/VITTY/ContentView.swift b/VITTY/ContentView.swift index 4d83241..2ccf005 100644 --- a/VITTY/ContentView.swift +++ b/VITTY/ContentView.swift @@ -16,7 +16,7 @@ struct ContentView: View { var body: some View { NavigationView { if authViewModel.loggedInFirebaseUser != nil { - if authViewModel.appUser == nil { + if authViewModel.loggedInBackendUser == nil { InstructionView() } else { diff --git a/VITTY/VITTY.xcodeproj/project.pbxproj b/VITTY/VITTY.xcodeproj/project.pbxproj index cf9a65c..3e10610 100644 --- a/VITTY/VITTY.xcodeproj/project.pbxproj +++ b/VITTY/VITTY.xcodeproj/project.pbxproj @@ -85,10 +85,11 @@ 525AA7A92B4B0164003C6A12 /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525AA7A82B4B0164003C6A12 /* SearchView.swift */; }; 525F759D2B809F8400E3B418 /* LectureDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525F759C2B809F8400E3B418 /* LectureDetailView.swift */; }; 527E3E082B7662920086F23D /* TimeTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 527E3E072B7662920086F23D /* TimeTableView.swift */; }; - 528CF16E2B769A84007298A0 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 528CF16D2B769A84007298A0 /* GoogleService-Info.plist */; }; 528CF1732B769B18007298A0 /* TimeTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 528CF1722B769B18007298A0 /* TimeTable.swift */; }; 528CF1762B769E22007298A0 /* TimeTableViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 528CF1752B769E22007298A0 /* TimeTableViewModel.swift */; }; 528CF1782B769E64007298A0 /* TimeTableAPIService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 528CF1772B769E64007298A0 /* TimeTableAPIService.swift */; }; + 52A81F992BD9F42500AED9B7 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 52A81F982BD9F42500AED9B7 /* GoogleService-Info.plist */; }; + 52A81F9B2BD9F42B00AED9B7 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 52A81F9A2BD9F42A00AED9B7 /* GoogleService-Info.plist */; }; 52D5AB862B6FE2ED00B2E66D /* AuthViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D5AB852B6FE2ED00B2E66D /* AuthViewModel.swift */; }; 52D5AB892B6FE3B200B2E66D /* AppUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D5AB882B6FE3B200B2E66D /* AppUser.swift */; }; 52D5AB8C2B6FE4D600B2E66D /* UserDefaultKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D5AB8B2B6FE4D500B2E66D /* UserDefaultKeys.swift */; }; @@ -178,11 +179,11 @@ 525AA7A82B4B0164003C6A12 /* SearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = ""; }; 525F759C2B809F8400E3B418 /* LectureDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LectureDetailView.swift; sourceTree = ""; }; 527E3E072B7662920086F23D /* TimeTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeTableView.swift; sourceTree = ""; }; - 528CF16D2B769A84007298A0 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "../../../../../../../Downloads/GoogleService-Info.plist"; sourceTree = ""; }; - 528CF16F2B769A89007298A0 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "../../../../../../../Downloads/GoogleService-Info.plist"; sourceTree = ""; }; 528CF1722B769B18007298A0 /* TimeTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeTable.swift; sourceTree = ""; }; 528CF1752B769E22007298A0 /* TimeTableViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeTableViewModel.swift; sourceTree = ""; }; 528CF1772B769E64007298A0 /* TimeTableAPIService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeTableAPIService.swift; sourceTree = ""; }; + 52A81F982BD9F42500AED9B7 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "../../../../../../../Downloads/GoogleService-Info.plist"; sourceTree = ""; }; + 52A81F9A2BD9F42A00AED9B7 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "../../../../../../../Downloads/GoogleService-Info.plist"; sourceTree = ""; }; 52D5AB852B6FE2ED00B2E66D /* AuthViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthViewModel.swift; sourceTree = ""; }; 52D5AB882B6FE3B200B2E66D /* AppUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUser.swift; sourceTree = ""; }; 52D5AB8B2B6FE4D500B2E66D /* UserDefaultKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultKeys.swift; sourceTree = ""; }; @@ -335,6 +336,7 @@ 314A408D27383BEC0058082F /* VITTY */ = { isa = PBXGroup; children = ( + 52A81F952BD9F41300AED9B7 /* Firebase */, 527E3E022B76626A0086F23D /* TimeTable */, 521562A92B70B0E50054F051 /* Instruction */, 52D5AB8A2B6FE4C600B2E66D /* Shared */, @@ -342,7 +344,6 @@ 5D1FF2632A32643400B0620A /* Settings */, 524B842C2B46EBA6006D18BD /* Home */, 524B84302B46EF07006D18BD /* Circle */, - 52DC41DF2B6F8B1500CCF8DB /* Firebase */, 52CC87082B677FCC0030B7E9 /* Auth */, 31128CF02772F0210084C9EA /* Info.plist */, 314A40A127383C0A0058082F /* Utilities */, @@ -624,6 +625,31 @@ path = Models; sourceTree = ""; }; + 52A81F952BD9F41300AED9B7 /* Firebase */ = { + isa = PBXGroup; + children = ( + 52A81F972BD9F41E00AED9B7 /* Prod */, + 52A81F962BD9F41A00AED9B7 /* Dev */, + ); + path = Firebase; + sourceTree = ""; + }; + 52A81F962BD9F41A00AED9B7 /* Dev */ = { + isa = PBXGroup; + children = ( + 52A81F9A2BD9F42A00AED9B7 /* GoogleService-Info.plist */, + ); + path = Dev; + sourceTree = ""; + }; + 52A81F972BD9F41E00AED9B7 /* Prod */ = { + isa = PBXGroup; + children = ( + 52A81F982BD9F42500AED9B7 /* GoogleService-Info.plist */, + ); + path = Prod; + sourceTree = ""; + }; 52CC87082B677FCC0030B7E9 /* Auth */ = { isa = PBXGroup; children = ( @@ -678,31 +704,6 @@ path = Views; sourceTree = ""; }; - 52DC41DF2B6F8B1500CCF8DB /* Firebase */ = { - isa = PBXGroup; - children = ( - 52DC41E12B6F8B2100CCF8DB /* Prod */, - 52DC41E02B6F8B1E00CCF8DB /* Dev */, - ); - path = Firebase; - sourceTree = ""; - }; - 52DC41E02B6F8B1E00CCF8DB /* Dev */ = { - isa = PBXGroup; - children = ( - 528CF16F2B769A89007298A0 /* GoogleService-Info.plist */, - ); - path = Dev; - sourceTree = ""; - }; - 52DC41E12B6F8B2100CCF8DB /* Prod */ = { - isa = PBXGroup; - children = ( - 528CF16D2B769A84007298A0 /* GoogleService-Info.plist */, - ); - path = Prod; - sourceTree = ""; - }; 5D1FF2632A32643400B0620A /* Settings */ = { isa = PBXGroup; children = ( @@ -866,7 +867,8 @@ 31128CF92772F57E0084C9EA /* Poppins-Medium.ttf in Resources */, 31128CFA2772F57E0084C9EA /* Poppins-SemiBoldItalic.ttf in Resources */, 31128CFC2772F57E0084C9EA /* Poppins-Regular.ttf in Resources */, - 528CF16E2B769A84007298A0 /* GoogleService-Info.plist in Resources */, + 52A81F992BD9F42500AED9B7 /* GoogleService-Info.plist in Resources */, + 52A81F9B2BD9F42B00AED9B7 /* GoogleService-Info.plist in Resources */, 314A409627383BEE0058082F /* Preview Assets.xcassets in Resources */, 314A409327383BEE0058082F /* Assets.xcassets in Resources */, ); diff --git a/VITTY/VITTY.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/VITTY/VITTY.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 039f9b7..41f9349 100644 --- a/VITTY/VITTY.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/VITTY/VITTY.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,12 +1,13 @@ { + "originHash" : "6f82248712b2a75248927c08ca58128690eff43fddf009041594657c80f6cd6d", "pins" : [ { "identity" : "abseil-cpp-binary", "kind" : "remoteSourceControl", "location" : "https://github.com/google/abseil-cpp-binary.git", "state" : { - "revision" : "bfc0b6f81adc06ce5121eb23f628473638d67c5c", - "version" : "1.2022062300.0" + "revision" : "748c7837511d0e6a507737353af268484e1745e2", + "version" : "1.2024011601.1" } }, { @@ -14,8 +15,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/Alamofire/Alamofire.git", "state" : { - "revision" : "3dc6a42c7727c49bf26508e29b0a0b35f9c7e1ad", - "version" : "5.8.1" + "revision" : "f455c2975872ccd2d9c81594c658af65716e9b9a", + "version" : "5.9.1" } }, { @@ -23,8 +24,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/app-check.git", "state" : { - "revision" : "3e464dad87dad2d29bb29a97836789bf0f8f67d2", - "version" : "10.18.1" + "revision" : "7d2688de038d5484866d835acb47b379722d610e", + "version" : "10.19.0" } }, { @@ -32,8 +33,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/openid/AppAuth-iOS.git", "state" : { - "revision" : "71cde449f13d453227e687458144bde372d30fc7", - "version" : "1.6.2" + "revision" : "c89ed571ae140f8eb1142735e6e23d7bb8c34cb2", + "version" : "1.7.5" } }, { @@ -41,8 +42,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/firebase/firebase-ios-sdk", "state" : { - "revision" : "f91c8167141d0279726c6f6d9d4a47c026785cbc", - "version" : "10.21.0" + "revision" : "42eae77a0af79e9c3f41df04a23c76f05cfdda77", + "version" : "10.24.0" } }, { @@ -50,8 +51,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/GoogleAppMeasurement.git", "state" : { - "revision" : "cb8617fab75d181270a1d8f763f26b15c73e2e1e", - "version" : "10.21.0" + "revision" : "51ba746a9d51a4bd0774b68499b0c73ef6e8570d", + "version" : "10.24.0" } }, { @@ -68,8 +69,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/GoogleSignIn-iOS", "state" : { - "revision" : "7932d33686c1dc4d7df7a919aae47361d1cdfda4", - "version" : "7.0.0" + "revision" : "a7965d134c5d3567026c523e0a8a583f73b62b0d", + "version" : "7.1.0" } }, { @@ -77,8 +78,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/GoogleUtilities.git", "state" : { - "revision" : "830ffa9276e10267881f2697283c2fcd867603fd", - "version" : "7.13.0" + "revision" : "26c898aed8bed13b8a63057ee26500abbbcb8d55", + "version" : "7.13.1" } }, { @@ -86,8 +87,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/grpc-binary.git", "state" : { - "revision" : "a673bc2937fbe886dd1f99c401b01b6d977a9c98", - "version" : "1.49.1" + "revision" : "e9fad491d0673bdda7063a0341fb6b47a30c5359", + "version" : "1.62.2" } }, { @@ -95,8 +96,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/gtm-session-fetcher.git", "state" : { - "revision" : "5ccda3981422a84186387dbb763ba739178b529c", - "version" : "2.3.0" + "revision" : "0382ca27f22fb3494cf657d8dc356dc282cd1193", + "version" : "3.4.1" } }, { @@ -104,8 +105,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/GTMAppAuth.git", "state" : { - "revision" : "6dee0cde8a1b223737a5159e55e6b4ec16bbbdd9", - "version" : "1.3.1" + "revision" : "5d7d66f647400952b1758b230e019b07c0b4b22a", + "version" : "4.1.1" } }, { @@ -122,8 +123,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/firebase/leveldb.git", "state" : { - "revision" : "43aaef65e0c665daadf848761d560e446d350d3d", - "version" : "1.22.4" + "revision" : "a0bc79961d7be727d258d33d5a6b2f1023270ba1", + "version" : "1.22.5" } }, { @@ -131,8 +132,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/firebase/nanopb.git", "state" : { - "revision" : "819d0a2173aff699fb8c364b6fb906f7cdb1a692", - "version" : "2.30909.0" + "revision" : "b7e1104502eca3a213b46303391ca4d3bc8ddec1", + "version" : "2.30910.0" } }, { @@ -149,8 +150,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-argument-parser.git", "state" : { - "revision" : "c8ed701b513cf5177118a175d85fbbbcd707ab41", - "version" : "1.3.0" + "revision" : "46989693916f56d1186bd59ac15124caef896560", + "version" : "1.3.1" } }, { @@ -185,8 +186,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-protobuf.git", "state" : { - "revision" : "65e8f29b2d63c4e38e736b25c27b83e012159be8", - "version" : "1.25.2" + "revision" : "9f0c76544701845ad98716f3f6a774a892152bcb", + "version" : "1.26.0" } }, { @@ -194,10 +195,10 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-syntax.git", "state" : { - "revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036", - "version" : "509.0.2" + "revision" : "64889f0c732f210a935a0ad7cda38f77f876262d", + "version" : "509.1.1" } } ], - "version" : 2 + "version" : 3 } diff --git a/VITTY/VITTY/Auth/Service/AuthAPIService.swift b/VITTY/VITTY/Auth/Service/AuthAPIService.swift index 429f580..6488567 100644 --- a/VITTY/VITTY/Auth/Service/AuthAPIService.swift +++ b/VITTY/VITTY/Auth/Service/AuthAPIService.swift @@ -14,7 +14,7 @@ enum AuthAPIServiceError: Error { class AuthAPIService { static let shared = AuthAPIService() - + func signInUser( with authRequestBody: AuthRequestBody ) async throws -> AppUser { @@ -29,7 +29,7 @@ class AuthAPIService { let appUser = try decoder.decode(AppUser.self, from: data.0) return appUser } - + func checkUserExists(with authID: String) async throws -> Bool { let url = URL(string: "\(Constants.url)auth/check-user-exists")! var request = URLRequest(url: url) @@ -37,7 +37,7 @@ class AuthAPIService { request.setValue("application/json", forHTTPHeaderField: "Content-Type") let encoder = JSONEncoder() request.httpBody = try encoder.encode(["uuid": authID]) - let (data, res) = try await URLSession.shared.data(for: request) + let (_, res) = try await URLSession.shared.data(for: request) let httpResponse = res as? HTTPURLResponse return httpResponse?.statusCode == 200 } diff --git a/VITTY/VITTY/Auth/ViewModels/AuthViewModel.swift b/VITTY/VITTY/Auth/ViewModels/AuthViewModel.swift index 2010d46..c88c2b5 100644 --- a/VITTY/VITTY/Auth/ViewModels/AuthViewModel.swift +++ b/VITTY/VITTY/Auth/ViewModels/AuthViewModel.swift @@ -11,6 +11,7 @@ import Firebase import FirebaseAuth import Foundation import GoogleSignIn +import OSLog enum LoginOption { case googleSignIn @@ -20,56 +21,81 @@ enum LoginOption { @Observable class AuthViewModel: NSObject, ASAuthorizationControllerDelegate { var loggedInFirebaseUser: User? - var appUser: AppUser? + var loggedInBackendUser: AppUser? var isLoading: Bool = false var error: NSError? let firebaseAuth = Auth.auth() fileprivate var currentNonce: String? - override init() { + private let logger = Logger( + subsystem: Bundle.main.bundleIdentifier!, + category: String( + describing: AuthViewModel.self + ) + ) + + + + override init() { + logger.info("Auth Initialization Started") + do { try firebaseAuth.useUserAccessGroup(nil) } catch { - print("Error: AuthViewModel(useUserAccessGroup)") + logger.error("\(error)") } - loggedInFirebaseUser = firebaseAuth.currentUser super.init() + + loggedInFirebaseUser = firebaseAuth.currentUser + firebaseAuth.addStateDidChangeListener(authViewModelChanged) + do { Task { if UserDefaults.standard.string(forKey: UserDefaultKeys.userKey) != nil { await signInServer( - username: UserDefaults.standard.string(forKey: UserDefaultKeys.userKey) ?? "", + username: UserDefaults.standard.string(forKey: UserDefaultKeys.userKey) + ?? "", regNo: "" ) } } } + + logger.info("Auth Initialization Ended") } - + private func authViewModelChanged(with auth: Auth, user: User?) { + logger.info("Auth State Changed") DispatchQueue.main.async { guard user != self.loggedInFirebaseUser else { return } self.loggedInFirebaseUser = user } } - - func login(with loginOption: LoginOption) async throws{ + + func login(with loginOption: LoginOption) async throws { + logger.info("Login Started") + isLoading = true error = nil - + switch loginOption { - case .googleSignIn: - try await signInWithGoogle() - case .appleSignIn: - signInWithApple() + case .googleSignIn: + logger.info("Google SignIn Started") + try await signInWithGoogle() + logger.info("Google SignIn Ended") + case .appleSignIn: + logger.info("Apple SignIn Started") + signInWithApple() + logger.info("Apple SignIn Ended") } + logger.info("Auth State Ended") } - + private func signInWithGoogle() async throws { - guard let screen = await UIApplication.shared.connectedScenes.first as? UIWindowScene else { + guard let screen = await UIApplication.shared.connectedScenes.first as? UIWindowScene else { return } guard let window = await screen.windows.first?.rootViewController else { return } @@ -84,20 +110,25 @@ class AuthViewModel: NSObject, ASAuthorizationControllerDelegate { userDefaultsStandard.set(authUser.user.providerID, forKey: UserDefaultKeys.providerIdKey) userDefaultsStandard.set(authUser.user.displayName, forKey: UserDefaultKeys.usernameKey) do { - let doesUserExist = try await AuthAPIService.shared.checkUserExists(with: authUser.user.uid) + let doesUserExist = try await AuthAPIService.shared.checkUserExists( + with: authUser.user.uid + ) if doesUserExist { - appUser = try await AuthAPIService.shared.signInUser(with: AuthRequestBody(uuid: authUser.user.uid, reg_no: "", username: "")) - UserDefaults.standard.set(appUser?.token, forKey: UserDefaultKeys.tokenKey) - UserDefaults.standard.set(appUser?.username, forKey: UserDefaultKeys.userKey) - UserDefaults.standard.set(appUser?.name, forKey: UserDefaultKeys.nameKey) - UserDefaults.standard.set(appUser?.picture, forKey: UserDefaultKeys.imageKey) + loggedInBackendUser = try await AuthAPIService.shared.signInUser( + with: AuthRequestBody(uuid: authUser.user.uid, reg_no: "", username: "") + ) + UserDefaults.standard.set(loggedInBackendUser?.token, forKey: UserDefaultKeys.tokenKey) + UserDefaults.standard.set(loggedInBackendUser?.username, forKey: UserDefaultKeys.userKey) + UserDefaults.standard.set(loggedInBackendUser?.name, forKey: UserDefaultKeys.nameKey) + UserDefaults.standard.set(loggedInBackendUser?.picture, forKey: UserDefaultKeys.imageKey) } - } catch { - print(error) + } + catch { + logger.error("\(error)") } self.isLoading = false } - + private func signInWithApple() { let nonce = AppleSignInUtilties.randomNonceString() currentNonce = nonce @@ -109,16 +140,16 @@ class AuthViewModel: NSObject, ASAuthorizationControllerDelegate { authController.delegate = self authController.performRequests() } - + internal func authorizationController( controller: ASAuthorizationController, didCompleteWithError error: Error ) { - print("Error signing in with Apple: \(error.localizedDescription)") + logger.error("Error signing in with Apple: \(error.localizedDescription)") isLoading = false self.error = error as NSError } - + internal func authorizationController( controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization @@ -130,24 +161,24 @@ class AuthViewModel: NSObject, ASAuthorizationControllerDelegate { ) } guard let appleIdToken = appleIdCred.identityToken else { - print("Unable to fetch identity token") + logger.error("Unable to fetch identity token") return } guard let idTokenString = String(data: appleIdToken, encoding: .utf8) else { - print( + logger.error( "Unable to serialize token string from data: \(appleIdToken.debugDescription)" ) return } guard let authCode = appleIdCred.authorizationCode else { - print("Unable to getch Authorization Code") + logger.error("Unable to getch Authorization Code") return } guard String(data: authCode, encoding: .utf8) != nil else { - print("Unable to serialize Authorization Code") + logger.error("Unable to serialize Authorization Code") return } - + let credential = OAuthProvider.credential( withProviderID: "apple.com", idToken: idTokenString, @@ -156,49 +187,61 @@ class AuthViewModel: NSObject, ASAuthorizationControllerDelegate { let authUser = try await firebaseAuth.signIn(with: credential) self.loggedInFirebaseUser = authUser.user let userDefaultsStandard = UserDefaults.standard - userDefaultsStandard.set(authUser.user.providerID, forKey: UserDefaultKeys.providerIdKey) + userDefaultsStandard.set( + authUser.user.providerID, + forKey: UserDefaultKeys.providerIdKey + ) userDefaultsStandard.set(authUser.user.displayName, forKey: UserDefaultKeys.usernameKey) do { - let doesUserExist = try await AuthAPIService.shared.checkUserExists(with: authUser.user.uid) + let doesUserExist = try await AuthAPIService.shared.checkUserExists( + with: authUser.user.uid + ) if doesUserExist { - appUser = try await AuthAPIService.shared.signInUser(with: AuthRequestBody(uuid: authUser.user.uid, reg_no: "", username: "")) - UserDefaults.standard.set(appUser?.token, forKey: UserDefaultKeys.tokenKey) - UserDefaults.standard.set(appUser?.username, forKey: UserDefaultKeys.userKey) - UserDefaults.standard.set(appUser?.name, forKey: UserDefaultKeys.nameKey) - UserDefaults.standard.set(appUser?.picture, forKey: UserDefaultKeys.imageKey) + loggedInBackendUser = try await AuthAPIService.shared.signInUser( + with: AuthRequestBody(uuid: authUser.user.uid, reg_no: "", username: "") + ) + UserDefaults.standard.set(loggedInBackendUser?.token, forKey: UserDefaultKeys.tokenKey) + UserDefaults.standard.set(loggedInBackendUser?.username, forKey: UserDefaultKeys.userKey) + UserDefaults.standard.set(loggedInBackendUser?.name, forKey: UserDefaultKeys.nameKey) + UserDefaults.standard.set(loggedInBackendUser?.picture, forKey: UserDefaultKeys.imageKey) } - } catch { - print(error) + } + catch { + logger.error("\(error)") } self.isLoading = false } else { - print("Error during authorization") + logger.error("Error during authorization") } } - + func signOut() { do { try firebaseAuth.signOut() - // TODO: create method to reset all UserDefaults UserDefaults.resetDefaults() } catch let signOutError as NSError { - print("Error Signing Out: \(signOutError)") + logger.error("Error Signing Out: \(signOutError)") } } - + func signInServer(username: String, regNo: String) async { + logger.info("Signing to Server Started") do { - self.appUser = try await AuthAPIService.shared - .signInUser(with: AuthRequestBody( - uuid: loggedInFirebaseUser?.uid ?? "", - reg_no: regNo, - username: username) + self.loggedInBackendUser = try await AuthAPIService.shared + .signInUser( + with: AuthRequestBody( + uuid: loggedInFirebaseUser?.uid ?? "", + reg_no: regNo, + username: username + ) ) - } catch { - print(error) } + catch { + logger.error("\(error)") + } + logger.info("Signing to Server Ended") } } @@ -206,10 +249,10 @@ private class AppleSignInUtilties { static func randomNonceString(length: Int = 32) -> String { precondition(length > 0) let charset: [Character] = - Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._") + Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._") var result = "" var remainingLength = length - + while remainingLength > 0 { let randoms: [UInt8] = (0..<16) .map { _ in @@ -222,29 +265,29 @@ private class AppleSignInUtilties { } return random } - + randoms.forEach { random in if length == 0 { return } - + if random < charset.count { result.append(charset[Int(random)]) remainingLength -= 1 } } } - + return result } static func sha256(_ input: String) -> String { let inputData = Data(input.utf8) let hashedData = SHA256.hash(data: inputData) let hashString = - hashedData.compactMap { - String(format: "%02x", $0) - } - .joined() + hashedData.compactMap { + String(format: "%02x", $0) + } + .joined() return hashString } } diff --git a/VITTY/VITTY/Circle/AddFriends/View/AddFriendsView.swift b/VITTY/VITTY/Circle/AddFriends/View/AddFriendsView.swift index d9b3310..162d7d9 100644 --- a/VITTY/VITTY/Circle/AddFriends/View/AddFriendsView.swift +++ b/VITTY/VITTY/Circle/AddFriends/View/AddFriendsView.swift @@ -84,7 +84,7 @@ struct AddFriendsView: View { .onAppear { suggestedFriendsViewModel.fetchData( from: "\(APIConstants.base_url)/api/v2/users/suggested/", - token: authViewModel.appUser?.token ?? "", + token: authViewModel.loggedInBackendUser?.token ?? "", loading: true ) } diff --git a/VITTY/VITTY/Circle/FriendRequest/ViewModel/FriendRequestViewModel.swift b/VITTY/VITTY/Circle/FriendRequest/ViewModel/FriendRequestViewModel.swift index ba30f0b..07be474 100644 --- a/VITTY/VITTY/Circle/FriendRequest/ViewModel/FriendRequestViewModel.swift +++ b/VITTY/VITTY/Circle/FriendRequest/ViewModel/FriendRequestViewModel.swift @@ -6,6 +6,7 @@ import Alamofire // Created by Chandram Dutta on 07/01/24. // import Foundation +import OSLog @Observable class FriendRequestViewModel { @@ -13,6 +14,13 @@ class FriendRequestViewModel { var requests = [Friend]() var loading = false var error = false + + private let logger = Logger( + subsystem: Bundle.main.bundleIdentifier!, + category: String( + describing: FriendRequestViewModel.self + ) + ) func fetchFriendRequests(from url: URL, authToken: String, loading: Bool) { self.loading = loading @@ -66,13 +74,13 @@ class FriendRequestViewModel { self.loading = false } catch { - print("Error decoding JSON: \(error)") + self.logger.error("Error decoding JSON: \(error)") self.error = true self.loading = false } case .failure(let error): - print("Error fetching data: \(error.localizedDescription)") + self.logger.error("Error fetching data: \(error.localizedDescription)") self.error = true self.loading = false } diff --git a/VITTY/VITTY/Circle/FriendRequest/Views/Components/FriendReqCard.swift b/VITTY/VITTY/Circle/FriendRequest/Views/Components/FriendReqCard.swift index 4e85df1..8aee376 100644 --- a/VITTY/VITTY/Circle/FriendRequest/Views/Components/FriendReqCard.swift +++ b/VITTY/VITTY/Circle/FriendRequest/Views/Components/FriendReqCard.swift @@ -5,6 +5,7 @@ // Created by Chandram Dutta on 07/01/24. // import SwiftUI +import OSLog struct FriendReqCard: View { @@ -12,6 +13,14 @@ struct FriendReqCard: View { @Environment(FriendRequestViewModel.self) private var friendRequestViewModel let friend: Friend + + private let logger = Logger( + subsystem: Bundle.main.bundleIdentifier!, + category: String( + describing: FriendReqCard.self + ) + ) + var body: some View { HStack { UserImage(url: friend.picture, height: 48, width: 48) @@ -34,7 +43,7 @@ struct FriendReqCard: View { request.httpMethod = "POST" request.addValue( - "Bearer \(authViewModel.appUser?.token ?? "")", + "Bearer \(authViewModel.loggedInBackendUser?.token ?? "")", forHTTPHeaderField: "Authorization" ) @@ -42,7 +51,7 @@ struct FriendReqCard: View { (data, response, error) in // Handle the response here if let error = error { - print("Error: \(error.localizedDescription)") + logger.error("\(error.localizedDescription)") return } @@ -50,10 +59,9 @@ struct FriendReqCard: View { // Parse the response data if needed do { let json = try JSONSerialization.jsonObject(with: data, options: []) - print("Response JSON: \(json)") } catch { - print("Error parsing response JSON: \(error.localizedDescription)") + logger.error("Error parsing response JSON: \(error.localizedDescription)") } } } @@ -63,7 +71,7 @@ struct FriendReqCard: View { friendRequestViewModel.fetchFriendRequests( from: URL(string: "\(APIConstants.base_url)/api/v2/requests/")!, - authToken: authViewModel.appUser?.token ?? "", + authToken: authViewModel.loggedInBackendUser?.token ?? "", loading: false ) @@ -80,7 +88,7 @@ struct FriendReqCard: View { request.httpMethod = "POST" request.addValue( - "Token \(authViewModel.appUser?.token ?? "")", + "Token \(authViewModel.loggedInBackendUser?.token ?? "")", forHTTPHeaderField: "Authorization" ) @@ -88,7 +96,7 @@ struct FriendReqCard: View { (data, response, error) in // Handle the response here if let error = error { - print("Error: \(error.localizedDescription)") + logger.error("Error: \(error.localizedDescription)") return } @@ -96,10 +104,9 @@ struct FriendReqCard: View { // Parse the response data if needed do { let json = try JSONSerialization.jsonObject(with: data, options: []) - print("Response JSON: \(json)") } catch { - print("Error parsing response JSON: \(error.localizedDescription)") + logger.error("Error parsing response JSON: \(error.localizedDescription)") } } } @@ -109,52 +116,13 @@ struct FriendReqCard: View { friendRequestViewModel.fetchFriendRequests( from: URL(string: "\(APIConstants.base_url)/api/v2/requests/")!, - authToken: authViewModel.appUser?.token ?? "", + authToken: authViewModel.loggedInBackendUser?.token ?? "", loading: false ) }) { Image(systemName: "person.fill.xmark") } } - // if friend.friendStatus != "sent" { - // Button("Send Request") { - // let url = URL(string: "\(APIConstants.base_url)/api/v2/requests/\(friend.username)/send")! - // var request = URLRequest(url: url) - // - // request.httpMethod = "POST" - // request.addValue("Bearer \(authViewModel.appUser?.token ?? "")", forHTTPHeaderField: "Authorization") - // - // let task = URLSession.shared.dataTask(with: request) { (data, response, error) in - // // Handle the response here - // if let error = error { - // print("Error: \(error.localizedDescription)") - // return - // } - // - // if let data = data { - // // Parse the response data if needed - // do { - // let json = try JSONSerialization.jsonObject(with: data, options: []) - // print("Response JSON: \(json)") - // } catch { - // print("Error parsing response JSON: \(error.localizedDescription)") - // } - // } - // } - // - // // Start the URLSession task - // task.resume() - // - // suggestedFriendsViewModel.fetchData( - // from: "\(APIConstants.base_url)/api/v2/users/suggested/", - // token: authViewModel.appUser?.token ?? "", - // loading: false - // ) - // }.buttonStyle(.bordered) - // .font(.caption) - // } else { - // Image(systemName: "person.fill.checkmark") - // } } } } diff --git a/VITTY/VITTY/Circle/FriendRequest/Views/FriendRequestView.swift b/VITTY/VITTY/Circle/FriendRequest/Views/FriendRequestView.swift index eff5664..d6469bd 100644 --- a/VITTY/VITTY/Circle/FriendRequest/Views/FriendRequestView.swift +++ b/VITTY/VITTY/Circle/FriendRequest/Views/FriendRequestView.swift @@ -34,7 +34,7 @@ struct FriendRequestView: View { .refreshable { friendRequestViewModel.fetchFriendRequests( from: URL(string: "\(APIConstants.base_url)/api/v2/requests/")!, - authToken: authViewModel.appUser?.token ?? "", + authToken: authViewModel.loggedInBackendUser?.token ?? "", loading: false ) diff --git a/VITTY/VITTY/Circle/Search/Views/SearchView.swift b/VITTY/VITTY/Circle/Search/Views/SearchView.swift index 2b9e9bd..cd26559 100644 --- a/VITTY/VITTY/Circle/Search/Views/SearchView.swift +++ b/VITTY/VITTY/Circle/Search/Views/SearchView.swift @@ -6,11 +6,20 @@ // import SwiftUI +import OSLog struct SearchView: View { @State private var searchText = "" @State private var searchedFriends = [Friend]() @State private var loading = false + + private let logger = Logger( + subsystem: Bundle.main.bundleIdentifier!, + category: String( + describing: SearchView.self + ) + ) + @Environment(AuthViewModel.self) private var authViewModel @Environment(\.dismiss) var dismiss var body: some View { @@ -77,7 +86,7 @@ struct SearchView: View { let session = URLSession.shared request.httpMethod = "GET" request.addValue( - "Bearer \(authViewModel.appUser?.token ?? "")", + "Bearer \(authViewModel.loggedInBackendUser?.token ?? "")", forHTTPHeaderField: "Authorization" ) if searchText.isEmpty { @@ -86,17 +95,17 @@ struct SearchView: View { else { let task = session.dataTask(with: request) { (data, response, error) in guard let data = data else { - print("No data received") + logger.warning("No data received") return } do { // Decode the JSON data into an array of UserInfo structs let users = try JSONDecoder().decode([Friend].self, from: data) - .filter { $0.username != authViewModel.appUser?.username ?? "" } + .filter { $0.username != authViewModel.loggedInBackendUser?.username ?? "" } searchedFriends = users } catch { - print("Error decoding JSON: \(error)") + logger.error("Error decoding JSON: \(error)") } } task.resume() diff --git a/VITTY/VITTY/Circle/SuggestedFriends/ViewModel/SuggestedFriendsViewModel.swift b/VITTY/VITTY/Circle/SuggestedFriends/ViewModel/SuggestedFriendsViewModel.swift index 6bf8084..7b0f7e6 100644 --- a/VITTY/VITTY/Circle/SuggestedFriends/ViewModel/SuggestedFriendsViewModel.swift +++ b/VITTY/VITTY/Circle/SuggestedFriends/ViewModel/SuggestedFriendsViewModel.swift @@ -7,6 +7,7 @@ import Alamofire import Foundation +import OSLog @Observable class SuggestedFriendsViewModel { @@ -14,6 +15,13 @@ class SuggestedFriendsViewModel { var suggestedFriends = [Friend]() var loading = false var error = false + + private let logger = Logger( + subsystem: Bundle.main.bundleIdentifier!, + category: String( + describing: SuggestedFriendsViewModel.self + ) + ) func fetchData(from url: String, token: String, loading: Bool) { self.loading = loading @@ -25,7 +33,7 @@ class SuggestedFriendsViewModel { self.suggestedFriends = data self.loading = false case .failure(let error): - print("Error fetching data: \(error)") + self.logger.error("Error fetching data: \(error)") self.loading = false self.error.toggle() } diff --git a/VITTY/VITTY/Circle/SuggestedFriends/Views/Components/AddFriendCard.swift b/VITTY/VITTY/Circle/SuggestedFriends/Views/Components/AddFriendCard.swift index ea64f02..4bba52c 100644 --- a/VITTY/VITTY/Circle/SuggestedFriends/Views/Components/AddFriendCard.swift +++ b/VITTY/VITTY/Circle/SuggestedFriends/Views/Components/AddFriendCard.swift @@ -6,11 +6,19 @@ // import SwiftUI +import OSLog struct AddFriendCard: View { @Environment(AuthViewModel.self) private var authViewModel @Environment(SuggestedFriendsViewModel.self) private var suggestedFriendsViewModel + + private let logger = Logger( + subsystem: Bundle.main.bundleIdentifier!, + category: String( + describing: AddFriendCard.self + ) + ) let friend: Friend var body: some View { @@ -42,7 +50,7 @@ struct AddFriendCard: View { (data, response, error) in // Handle the response here if let error = error { - print("Error: \(error.localizedDescription)") + logger.error("\(error.localizedDescription)") return } @@ -50,10 +58,9 @@ struct AddFriendCard: View { // Parse the response data if needed do { let json = try JSONSerialization.jsonObject(with: data, options: []) - print("Response JSON: \(json)") } catch { - print("Error parsing response JSON: \(error.localizedDescription)") + logger.error("Error parsing response JSON: \(error.localizedDescription)") } } } @@ -63,7 +70,7 @@ struct AddFriendCard: View { suggestedFriendsViewModel.fetchData( from: "\(APIConstants.base_url)/api/v2/users/suggested/", - token: authViewModel.appUser?.token ?? "", + token: authViewModel.loggedInBackendUser?.token ?? "", loading: false ) } diff --git a/VITTY/VITTY/Circle/SuggestedFriends/Views/SuggestedFriendsView.swift b/VITTY/VITTY/Circle/SuggestedFriends/Views/SuggestedFriendsView.swift index 090fe94..e4ca60d 100644 --- a/VITTY/VITTY/Circle/SuggestedFriends/Views/SuggestedFriendsView.swift +++ b/VITTY/VITTY/Circle/SuggestedFriends/Views/SuggestedFriendsView.swift @@ -34,7 +34,7 @@ struct SuggestedFriendsView: View { .refreshable { suggestedFriendsViewModel.fetchData( from: "\(APIConstants.base_url)/api/v2/users/suggested/", - token: authViewModel.appUser?.token ?? "", + token: authViewModel.loggedInBackendUser?.token ?? "", loading: false ) } diff --git a/VITTY/VITTY/Circle/View/CommunityPage.swift b/VITTY/VITTY/Circle/View/CommunityPage.swift index 375cbf8..f46b6a0 100644 --- a/VITTY/VITTY/Circle/View/CommunityPage.swift +++ b/VITTY/VITTY/Circle/View/CommunityPage.swift @@ -10,7 +10,7 @@ import SwiftUI struct CommunityPage: View { @Environment(AuthViewModel.self) private var authViewModel -// @EnvironmentObject private var timeTableViewModel: TimetableViewModel + // @EnvironmentObject private var timeTableViewModel: TimetableViewModel @Environment(CommunityPageViewModel.self) private var communityPageViewModel @State private var isShowingRequestView = false @@ -84,8 +84,8 @@ struct CommunityPage: View { .refreshable { communityPageViewModel.fetchData( from: - "\(APIConstants.base_url)/api/v2/friends/\(authViewModel.appUser?.username ?? "")/", - token: authViewModel.appUser?.token ?? "", + "\(APIConstants.base_url)/api/v2/friends/\(authViewModel.loggedInBackendUser?.username ?? "")/", + token: authViewModel.loggedInBackendUser?.token ?? "", loading: false ) } @@ -118,8 +118,8 @@ struct CommunityPage: View { .onAppear { communityPageViewModel.fetchData( from: - "\(APIConstants.base_url)/api/v2/friends/\(authViewModel.appUser?.username ?? "")/", - token: authViewModel.appUser?.token ?? "", + "\(APIConstants.base_url)/api/v2/friends/\(authViewModel.loggedInBackendUser?.username ?? "")/", + token: authViewModel.loggedInBackendUser?.token ?? "", loading: true ) } diff --git a/VITTY/VITTY/Circle/View/Components/CommunityPageHeader.swift b/VITTY/VITTY/Circle/View/Components/CommunityPageHeader.swift index ee8a290..c813258 100644 --- a/VITTY/VITTY/Circle/View/Components/CommunityPageHeader.swift +++ b/VITTY/VITTY/Circle/View/Components/CommunityPageHeader.swift @@ -39,7 +39,7 @@ struct CommunityPageHeader: View { .onAppear { friendRequestViewModel.fetchFriendRequests( from: URL(string: "\(APIConstants.base_url)/api/v2/requests/")!, - authToken: authViewModel.appUser?.token ?? "", + authToken: authViewModel.loggedInBackendUser?.token ?? "", loading: true ) } @@ -50,8 +50,8 @@ struct CommunityPageHeader: View { onDismiss: { communityPageViewModel.fetchData( from: - "\(APIConstants.base_url)/api/v2/friends/\(authViewModel.appUser?.username ?? "")/", - token: authViewModel.appUser?.token ?? "", + "\(APIConstants.base_url)/api/v2/friends/\(authViewModel.loggedInBackendUser?.username ?? "")/", + token: authViewModel.loggedInBackendUser?.token ?? "", loading: true ) }, diff --git a/VITTY/VITTY/Circle/ViewModel/CommunityPageViewModel.swift b/VITTY/VITTY/Circle/ViewModel/CommunityPageViewModel.swift index 36424b5..d889abf 100644 --- a/VITTY/VITTY/Circle/ViewModel/CommunityPageViewModel.swift +++ b/VITTY/VITTY/Circle/ViewModel/CommunityPageViewModel.swift @@ -7,6 +7,7 @@ import Alamofire import Foundation +import OSLog @Observable class CommunityPageViewModel { @@ -14,6 +15,13 @@ class CommunityPageViewModel { var friends = [Friend]() var loading = false var error = false + + private let logger = Logger( + subsystem: Bundle.main.bundleIdentifier!, + category: String( + describing: CommunityPageViewModel.self + ) + ) func fetchData(from url: String, token: String, loading: Bool) { self.loading = loading @@ -25,7 +33,7 @@ class CommunityPageViewModel { self.friends = data.data self.loading = false case .failure(let error): - print("Error fetching data: \(error)") + self.logger.error("Error fetching data: \(error)") self.loading = false self.error.toggle() } diff --git a/VITTY/VITTY/Instruction/Views/InstructionView.swift b/VITTY/VITTY/Instruction/Views/InstructionView.swift index 520172a..61ac5f7 100644 --- a/VITTY/VITTY/Instruction/Views/InstructionView.swift +++ b/VITTY/VITTY/Instruction/Views/InstructionView.swift @@ -85,7 +85,7 @@ struct InstructionView: View { } .padding(.vertical) NavigationLink(destination: { - if authViewModel.appUser == nil { + if authViewModel.loggedInBackendUser == nil { UsernameView() } else { diff --git a/VITTY/VITTY/TimeTable/Models/TimeTable.swift b/VITTY/VITTY/TimeTable/Models/TimeTable.swift index d000a0e..1b4c6ae 100644 --- a/VITTY/VITTY/TimeTable/Models/TimeTable.swift +++ b/VITTY/VITTY/TimeTable/Models/TimeTable.swift @@ -6,6 +6,7 @@ // import Foundation +import OSLog //import SwiftData @@ -26,6 +27,12 @@ class TimeTable: Codable { let friday: [Lecture] let saturday: [Lecture] let sunday: [Lecture] + private let logger = Logger( + subsystem: Bundle.main.bundleIdentifier!, + category: String( + describing: TimeTable.self + ) + ) init( monday: [Lecture], @@ -62,7 +69,7 @@ class TimeTable: Codable { monday = try container.decode([Lecture].self, forKey: .monday) } catch { - print("Error decoding Monday lectures:", error) + logger.error("Error decoding Monday lectures: \(error)") monday = [] } @@ -70,7 +77,7 @@ class TimeTable: Codable { tuesday = try container.decode([Lecture].self, forKey: .tuesday) } catch { - print("Error decoding Tuesday lectures:", error) + logger.error("Error decoding Tuesday lectures: \(error)") tuesday = [] } @@ -78,7 +85,7 @@ class TimeTable: Codable { wednesday = try container.decode([Lecture].self, forKey: .wednesday) } catch { - print("Error decoding Wednesday lectures:", error) + logger.error("Error decoding Wednesday lectures: \(error)") wednesday = [] } @@ -86,7 +93,7 @@ class TimeTable: Codable { thursday = try container.decode([Lecture].self, forKey: .thursday) } catch { - print("Error decoding Thursday lectures:", error) + logger.error("Error decoding Thursday lectures: \(error)") thursday = [] } @@ -94,7 +101,7 @@ class TimeTable: Codable { friday = try container.decode([Lecture].self, forKey: .friday) } catch { - print("Error decoding Friday lectures:", error) + logger.error("Error decoding Friday lectures: \(error)") friday = [] } @@ -102,7 +109,7 @@ class TimeTable: Codable { saturday = try container.decode([Lecture].self, forKey: .saturday) } catch { - print("Error decoding Saturday lectures:", error) + logger.error("Error decoding Saturday lectures: \(error)") saturday = [] } @@ -110,7 +117,7 @@ class TimeTable: Codable { sunday = try container.decode([Lecture].self, forKey: .sunday) } catch { - print("Error decoding Sunday lectures:", error) + logger.error("Error decoding Sunday lectures: \(error)") sunday = [] } } diff --git a/VITTY/VITTY/TimeTable/Service/TimeTableAPIService.swift b/VITTY/VITTY/TimeTable/Service/TimeTableAPIService.swift index a91f120..803fb1e 100644 --- a/VITTY/VITTY/TimeTable/Service/TimeTableAPIService.swift +++ b/VITTY/VITTY/TimeTable/Service/TimeTableAPIService.swift @@ -13,8 +13,8 @@ class TimeTableAPIService { func getTimeTable( with username: String, authToken: String - ) async throws -> TimeTable { - + ) async throws -> TimeTable { + let url = URL(string: "\(Constants.url)timetable/\(username)")! var request = URLRequest(url: url) request.httpMethod = "GET" diff --git a/VITTY/VITTY/TimeTable/ViewModel/TimeTableViewModel.swift b/VITTY/VITTY/TimeTable/ViewModel/TimeTableViewModel.swift index 1b4c9f8..6a19456 100644 --- a/VITTY/VITTY/TimeTable/ViewModel/TimeTableViewModel.swift +++ b/VITTY/VITTY/TimeTable/ViewModel/TimeTableViewModel.swift @@ -7,6 +7,7 @@ import Foundation import SwiftData +import OSLog public enum Stage { case loading @@ -23,6 +24,12 @@ extension TimeTableView { var stage: Stage = .loading var lectures = [Lecture]() var dayNo = Date.convertToMondayWeek() + private let logger = Logger( + subsystem: Bundle.main.bundleIdentifier!, + category: String( + describing: TimeTableViewModel.self + ) + ) func changeDay() { switch dayNo { @@ -46,16 +53,23 @@ extension TimeTableView { } func fetchTimeTable(username: String, authToken: String) async { + logger.info("Fetching TimeTable Started") do { stage = .loading - let data = try await TimeTableAPIService.shared.getTimeTable(with: username, authToken: authToken) + let data = try await TimeTableAPIService.shared.getTimeTable( + with: username, + authToken: authToken + ) + logger.info("TimeTable Fetched from API") timeTable = data changeDay() stage = .data - } catch { - print(error) + } + catch { + logger.error("\(error)") stage = .error } + logger.info("Fetching TimeTable Ended") } } } diff --git a/VITTY/VITTY/TimeTable/Views/LectureDetailView.swift b/VITTY/VITTY/TimeTable/Views/LectureDetailView.swift index 1dc6d13..c0e3d9a 100644 --- a/VITTY/VITTY/TimeTable/Views/LectureDetailView.swift +++ b/VITTY/VITTY/TimeTable/Views/LectureDetailView.swift @@ -19,6 +19,9 @@ struct LectureDetailView: View { Marker(lecture.venue, coordinate: determineCoordinates(venue: lecture.venue)) } .mapStyle(.standard) +// .mapControls{ +// MapUserLocationButton() +// } VStack(alignment: .leading) { HStack { Text(lecture.name) diff --git a/VITTY/VITTY/TimeTable/Views/TimeTableView.swift b/VITTY/VITTY/TimeTable/Views/TimeTableView.swift index 42aa65b..bd5cbfb 100644 --- a/VITTY/VITTY/TimeTable/Views/TimeTableView.swift +++ b/VITTY/VITTY/TimeTable/Views/TimeTableView.swift @@ -7,6 +7,7 @@ import SwiftData import SwiftUI +import OSLog struct TimeTableView: View { @Environment(AuthViewModel.self) private var authViewModel @@ -16,6 +17,13 @@ struct TimeTableView: View { @State private var selectedLecture: Lecture? = nil let friend: Friend? + + private let logger = Logger( + subsystem: Bundle.main.bundleIdentifier!, + category: String( + describing: TimeTableView.self + ) + ) var body: some View { NavigationStack { @@ -24,131 +32,141 @@ struct TimeTableView: View { .resizable() .ignoresSafeArea() switch viewModel.stage { - case .loading: - VStack { - Spacer() - ProgressView() - Spacer() - } - case .error: - VStack{ - Spacer() - Text("It's an error!") - .font(Font.custom("Poppins-Bold", size: 24)) - Text("Sorry if you are late for your class!") - Spacer() - } - case .data: - VStack { - ScrollView(.horizontal) { - HStack { - ForEach(daysOfWeek, id: \.self) { day in - Text(day) - .frame(width: 60, height: 54) - .background( - daysOfWeek[viewModel.dayNo] == day - ? Color(Color.theme.secondary) : Color.clear - ) - .onTapGesture { - withAnimation { - viewModel.dayNo = daysOfWeek.firstIndex(of: day)! - viewModel.changeDay() - } - } - .clipShape(RoundedRectangle(cornerRadius: 10)) - } - } + case .loading: + VStack { + Spacer() + ProgressView() + Spacer() } - .scrollIndicators(.hidden) - .background(Color("DarkBG")) - .clipShape(RoundedRectangle(cornerRadius: 10)) - .padding(.horizontal) - if viewModel.lectures == [] { + case .error: + VStack { Spacer() - Text("No classes today!") + Text("It's an error!") .font(Font.custom("Poppins-Bold", size: 24)) - Text(StringConstants.noClassQuotesOffline.randomElement()!) - } else { - List(viewModel.lectures.sorted()) { lecture in - VStack(alignment: .leading) { - Text(lecture.name) - .font(.headline) - HStack { - Text( - "\(formatTime(time: lecture.startTime)) - \(formatTime(time: lecture.endTime))" - ) - Spacer() - Text("\(lecture.venue)") + Text("Sorry if you are late for your class!") + Spacer() + } + case .data: + VStack(spacing: 0) { + ScrollView(.horizontal) { + HStack { + ForEach(daysOfWeek, id: \.self) { day in + Text(day) + .frame(width: 60, height: 54) + .background( + daysOfWeek[viewModel.dayNo] == day + ? Color(Color.theme.secondary) : Color.clear + ) + .onTapGesture { + withAnimation { + viewModel.dayNo = daysOfWeek.firstIndex( + of: day + )! + viewModel.changeDay() + } + } + .clipShape(RoundedRectangle(cornerRadius: 10)) } - .foregroundColor(Color.vprimary) - .font(.caption) } - .onTapGesture { - selectedLecture = lecture - } - .listRowBackground(Color("DarkBG")) } - .sheet(item: $selectedLecture) { lecture in - LectureDetailView(lecture: lecture) + .scrollIndicators(.hidden) + .background(Color("DarkBG")) + .clipShape(RoundedRectangle(cornerRadius: 10)) + .padding(.horizontal) + if viewModel.lectures == [] { + Spacer() + Text("No classes today!") + .font(Font.custom("Poppins-Bold", size: 24)) + Text(StringConstants.noClassQuotesOffline.randomElement()!) + } + else { + List(viewModel.lectures.sorted()) { lecture in + VStack(alignment: .leading) { + Text(lecture.name) + .font(.headline) + HStack { + Text( + "\(formatTime(time: lecture.startTime)) - \(formatTime(time: lecture.endTime))" + ) + Spacer() + Text("\(lecture.venue)") + } + .foregroundColor(Color.vprimary) + .font(.caption) + } + .onTapGesture { + selectedLecture = lecture + } + .padding(.bottom) + .listRowBackground( + RoundedRectangle(cornerRadius: 15).fill(Color.theme.secondaryBlue) + .padding(.bottom) + ) + .listRowSeparator(.hidden) + } + .sheet(item: $selectedLecture) { lecture in + LectureDetailView(lecture: lecture) + } + .scrollContentBackground(.hidden) } - .scrollContentBackground(.hidden) + Spacer() } - Spacer() - } } - + } .navigationTitle(friend?.name ?? "Schedule") .toolbar { - Menu { - if friend == nil { - NavigationLink { - SettingsView() - } label: { - Label("Settings", systemImage: "gear") - } - Button(role: .destructive) { - authViewModel.signOut() - } label: { - Label("Logout", systemImage: "rectangle.portrait.and.arrow.right") - } - } else { - Button{ - let url = URL( - string: "\(APIConstants.base_url)/api/v2/friends/\(friend?.username ?? "")" - )! - var request = URLRequest(url: url) - request.httpMethod = "DELETE" - request.addValue( - "Token \(authViewModel.appUser?.token ?? "")", - forHTTPHeaderField: "Authorization" - ) - let task = URLSession.shared.dataTask(with: request) { - (data, response, error) in - if let error = error { - print("Error: \(error.localizedDescription)") - return - } + Menu { + if friend == nil { + NavigationLink { + SettingsView() + } label: { + Label("Settings", systemImage: "gear") + } + Button(role: .destructive) { + authViewModel.signOut() + } label: { + Label("Logout", systemImage: "rectangle.portrait.and.arrow.right") + } + } + else { + Button { + let url = URL( + string: + "\(APIConstants.base_url)/api/v2/friends/\(friend?.username ?? "")" + )! + var request = URLRequest(url: url) + request.httpMethod = "DELETE" + request.addValue( + "Token \(authViewModel.loggedInBackendUser?.token ?? "")", + forHTTPHeaderField: "Authorization" + ) + let task = URLSession.shared.dataTask(with: request) { + (data, response, error) in + if let error = error { + logger.error("\(error.localizedDescription)") + return } - task.resume() - } label: { - Label("Unfriend", systemImage: "person.fill.xmark") } + task.resume() + } label: { + Label("Unfriend", systemImage: "person.fill.xmark") } - } label: { - UserImage( - url: friend?.picture ?? (authViewModel.appUser?.picture ?? ""), - height: 30, - width: 40 - ) } + } label: { + UserImage( + url: friend?.picture ?? (authViewModel.loggedInBackendUser?.picture ?? ""), + height: 30, + width: 40 + ) + } } } .onAppear { Task { - await viewModel.fetchTimeTable ( - username: friend?.username ?? (authViewModel.appUser?.username ?? ""), - authToken: authViewModel.appUser?.token ?? "" + await viewModel.fetchTimeTable( + username: friend?.username ?? (authViewModel.loggedInBackendUser?.username ?? ""), + authToken: authViewModel.loggedInBackendUser?.token ?? "" ) } } diff --git a/VITTY/VITTY/Username/Views/UsernameView.swift b/VITTY/VITTY/Username/Views/UsernameView.swift index 3ff25a5..2173e41 100644 --- a/VITTY/VITTY/Username/Views/UsernameView.swift +++ b/VITTY/VITTY/Username/Views/UsernameView.swift @@ -86,7 +86,7 @@ struct UsernameView: View { Spacer() Button(action: { Task { - + isLoading = true await authViewModel.signInServer(username: username, regNo: regNo) isLoading = false diff --git a/VITTY/VITTY/Utilities/Constants/StringConstants.swift b/VITTY/VITTY/Utilities/Constants/StringConstants.swift index 2a780a2..5f70e1e 100644 --- a/VITTY/VITTY/Utilities/Constants/StringConstants.swift +++ b/VITTY/VITTY/Utilities/Constants/StringConstants.swift @@ -65,16 +65,16 @@ struct StringConstants { static let setupFinalText = "BRAVO! That's it. You did it!" static let followInstructionsText = "Fetching information. Follow the instructions given below" -// // MARK: CLASS DATA -// static let sampleClassDate = Classes( -// courseType: "Theory", -// courseCode: "MAT3004", -// courseName: "Applied Linear Algebra", -// location: "SJT112", -// slot: "A1", -// startTime: Date(), -// endTime: Date(timeIntervalSinceNow: 3600) -// ) + // // MARK: CLASS DATA + // static let sampleClassDate = Classes( + // courseType: "Theory", + // courseCode: "MAT3004", + // courseName: "Applied Linear Algebra", + // location: "SJT112", + // slot: "A1", + // startTime: Date(), + // endTime: Date(timeIntervalSinceNow: 3600) + // ) // MARK: RANDOM STRINGS static let noClassQuotesOnline = [ diff --git a/VITTY/VITTYApp.swift b/VITTY/VITTYApp.swift index cfdd494..1a58e18 100644 --- a/VITTY/VITTYApp.swift +++ b/VITTY/VITTYApp.swift @@ -6,44 +6,51 @@ // import Firebase -import GoogleSignIn -import SwiftData import SwiftUI +import OSLog /** `NOTE FOR FUTURE/NEW DEVS:` - + - always use the latest and greatest apple tools, don't use something that's been replaced by apple (start watching WWDC to stay updated) for eg: use SwiftData and not CoreData. use @Observable and not ObservableObject and u don't want to use UIKit instead of SwiftUI. trust me on this. reason: it makes the code more future proof and incase there's no activity on the development for a year, the app wont be outdated. downside: minimum deployment target has to be raised which hurts adoption but apple doesn't care about this either so we don't too. - + `personal experience, we have had issues when this app would just crash for iOS 16+ because the code were not updated.` `we lost a lot of users and our ratings dropped to 3.` - + - continuation to the first point, pls replace parts of the app that uses these old tech as soon as you can. - + - focus on keeping the package dependencies on latest versions - + - use `swift-format` to format the code before pushing. it's already configured for the project. double click on VITTY on left panel and click on format code. - + - use `tabs` and `not` spaces pls. - + - try to focus on subtle animations and transitions. it makes the app feel more polished. `withAnimation{ }` is the greatest tool ever made by apple. - + - try to use haptics wherever possible. users love to feel those and apple makes it easier for us to implement - + - try to stick to Apple HIG as much as possible. ik it's difficult considering the UI we have now but it's worth it. - + - use // MARK: when u create a function, it helps to navigate. */ @main struct VITTYApp: App { + + private let logger = Logger( + subsystem: Bundle.main.bundleIdentifier!, + category: String( + describing: VITTYApp.self + ) + ) + init() { setupFirebase() } - + var body: some Scene { WindowGroup { ContentView() @@ -54,6 +61,8 @@ struct VITTYApp: App { extension VITTYApp { private func setupFirebase() { + self.logger.info("Configuring Firebase Started") FirebaseApp.configure() + self.logger.info("Configuring Firebase Ended") } } diff --git a/VITTY/vittywidget/AppIntent.swift b/VITTY/vittywidget/AppIntent.swift index 9a468ad..ea810fc 100644 --- a/VITTY/vittywidget/AppIntent.swift +++ b/VITTY/vittywidget/AppIntent.swift @@ -5,14 +5,14 @@ // Created by Chandram Dutta on 04/03/24. // -import WidgetKit import AppIntents +import WidgetKit struct ConfigurationAppIntent: WidgetConfigurationIntent { - static var title: LocalizedStringResource = "Configuration" - static var description = IntentDescription("This is an example widget.") + static var title: LocalizedStringResource = "Configuration" + static var description = IntentDescription("This is an example widget.") - // An example configurable parameter. - @Parameter(title: "Favorite Emoji", default: "😃") - var favoriteEmoji: String + // An example configurable parameter. + @Parameter(title: "Favorite Emoji", default: "😃") + var favoriteEmoji: String } diff --git a/VITTY/vittywidget/vittywidget.swift b/VITTY/vittywidget/vittywidget.swift index ef52d40..38b1e20 100644 --- a/VITTY/vittywidget/vittywidget.swift +++ b/VITTY/vittywidget/vittywidget.swift @@ -5,80 +5,94 @@ // Created by Chandram Dutta on 04/03/24. // -import WidgetKit import SwiftUI +import WidgetKit struct Provider: AppIntentTimelineProvider { - func placeholder(in context: Context) -> SimpleEntry { - SimpleEntry(date: Date(), configuration: ConfigurationAppIntent()) - } + func placeholder(in context: Context) -> SimpleEntry { + SimpleEntry(date: Date(), configuration: ConfigurationAppIntent()) + } - func snapshot(for configuration: ConfigurationAppIntent, in context: Context) async -> SimpleEntry { - SimpleEntry(date: Date(), configuration: configuration) - } - - func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline<SimpleEntry> { - var entries: [SimpleEntry] = [] + func snapshot( + for configuration: ConfigurationAppIntent, + in context: Context + ) async -> SimpleEntry { + SimpleEntry(date: Date(), configuration: configuration) + } - // Generate a timeline consisting of five entries an hour apart, starting from the current date. - let currentDate = Date() - for hourOffset in 0 ..< 5 { - let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! - let entry = SimpleEntry(date: entryDate, configuration: configuration) - entries.append(entry) - } + func timeline( + for configuration: ConfigurationAppIntent, + in context: Context + ) async -> Timeline<SimpleEntry> { + var entries: [SimpleEntry] = [] - return Timeline(entries: entries, policy: .atEnd) - } + // Generate a timeline consisting of five entries an hour apart, starting from the current date. + let currentDate = Date() + for hourOffset in 0..<5 { + let entryDate = Calendar.current.date( + byAdding: .hour, + value: hourOffset, + to: currentDate + )! + let entry = SimpleEntry(date: entryDate, configuration: configuration) + entries.append(entry) + } + + return Timeline(entries: entries, policy: .atEnd) + } } struct SimpleEntry: TimelineEntry { - let date: Date - let configuration: ConfigurationAppIntent + let date: Date + let configuration: ConfigurationAppIntent } -struct vittywidgetEntryView : View { - var entry: Provider.Entry +struct vittywidgetEntryView: View { + var entry: Provider.Entry - var body: some View { - VStack { - Text("Time:") - Text(entry.date, style: .time) + var body: some View { + VStack { + Text("Time:") + Text(entry.date, style: .time) - Text("Favorite Emoji:") - Text(entry.configuration.favoriteEmoji) - } - } + Text("Favorite Emoji:") + Text(entry.configuration.favoriteEmoji) + } + } } struct vittywidget: Widget { - let kind: String = "vittywidget" + let kind: String = "vittywidget" - var body: some WidgetConfiguration { - AppIntentConfiguration(kind: kind, intent: ConfigurationAppIntent.self, provider: Provider()) { entry in - vittywidgetEntryView(entry: entry) - .containerBackground(.fill.tertiary, for: .widget) - } - } + var body: some WidgetConfiguration { + AppIntentConfiguration( + kind: kind, + intent: ConfigurationAppIntent.self, + provider: Provider() + ) { entry in + vittywidgetEntryView(entry: entry) + .containerBackground(.fill.tertiary, for: .widget) + } + } } extension ConfigurationAppIntent { - fileprivate static var smiley: ConfigurationAppIntent { - let intent = ConfigurationAppIntent() - intent.favoriteEmoji = "😀" - return intent - } - - fileprivate static var starEyes: ConfigurationAppIntent { - let intent = ConfigurationAppIntent() - intent.favoriteEmoji = "🤩" - return intent - } + fileprivate static var smiley: ConfigurationAppIntent { + let intent = ConfigurationAppIntent() + intent.favoriteEmoji = "😀" + return intent + } + + fileprivate static var starEyes: ConfigurationAppIntent { + let intent = ConfigurationAppIntent() + intent.favoriteEmoji = "🤩" + return intent + } } #Preview(as: .systemSmall) { - vittywidget() + vittywidget() } timeline: { - SimpleEntry(date: .now, configuration: .smiley) - SimpleEntry(date: .now, configuration: .starEyes) + SimpleEntry(date: .now, configuration: .smiley) + SimpleEntry(date: .now, configuration: .starEyes) } diff --git a/VITTY/vittywidget/vittywidgetBundle.swift b/VITTY/vittywidget/vittywidgetBundle.swift index ff8354e..197188b 100644 --- a/VITTY/vittywidget/vittywidgetBundle.swift +++ b/VITTY/vittywidget/vittywidgetBundle.swift @@ -5,13 +5,13 @@ // Created by Chandram Dutta on 04/03/24. // -import WidgetKit import SwiftUI +import WidgetKit @main struct vittywidgetBundle: WidgetBundle { - var body: some Widget { - vittywidget() - vittywidgetLiveActivity() - } + var body: some Widget { + vittywidget() + vittywidgetLiveActivity() + } } diff --git a/VITTY/vittywidget/vittywidgetLiveActivity.swift b/VITTY/vittywidget/vittywidgetLiveActivity.swift index 712c104..83a5d03 100644 --- a/VITTY/vittywidget/vittywidgetLiveActivity.swift +++ b/VITTY/vittywidget/vittywidgetLiveActivity.swift @@ -6,75 +6,75 @@ // import ActivityKit -import WidgetKit import SwiftUI +import WidgetKit struct vittywidgetAttributes: ActivityAttributes { - public struct ContentState: Codable, Hashable { - // Dynamic stateful properties about your activity go here! - var emoji: String - } + public struct ContentState: Codable, Hashable { + // Dynamic stateful properties about your activity go here! + var emoji: String + } - // Fixed non-changing properties about your activity go here! - var name: String + // Fixed non-changing properties about your activity go here! + var name: String } struct vittywidgetLiveActivity: Widget { - var body: some WidgetConfiguration { - ActivityConfiguration(for: vittywidgetAttributes.self) { context in - // Lock screen/banner UI goes here - VStack { - Text("Hello \(context.state.emoji)") - } - .activityBackgroundTint(Color.cyan) - .activitySystemActionForegroundColor(Color.black) + var body: some WidgetConfiguration { + ActivityConfiguration(for: vittywidgetAttributes.self) { context in + // Lock screen/banner UI goes here + VStack { + Text("Hello \(context.state.emoji)") + } + .activityBackgroundTint(Color.cyan) + .activitySystemActionForegroundColor(Color.black) - } dynamicIsland: { context in - DynamicIsland { - // Expanded UI goes here. Compose the expanded UI through - // various regions, like leading/trailing/center/bottom - DynamicIslandExpandedRegion(.leading) { - Text("Leading") - } - DynamicIslandExpandedRegion(.trailing) { - Text("Trailing") - } - DynamicIslandExpandedRegion(.bottom) { - Text("Bottom \(context.state.emoji)") - // more content - } - } compactLeading: { - Text("L") - } compactTrailing: { - Text("T \(context.state.emoji)") - } minimal: { - Text(context.state.emoji) - } - .widgetURL(URL(string: "http://www.apple.com")) - .keylineTint(Color.red) - } - } + } dynamicIsland: { context in + DynamicIsland { + // Expanded UI goes here. Compose the expanded UI through + // various regions, like leading/trailing/center/bottom + DynamicIslandExpandedRegion(.leading) { + Text("Leading") + } + DynamicIslandExpandedRegion(.trailing) { + Text("Trailing") + } + DynamicIslandExpandedRegion(.bottom) { + Text("Bottom \(context.state.emoji)") + // more content + } + } compactLeading: { + Text("L") + } compactTrailing: { + Text("T \(context.state.emoji)") + } minimal: { + Text(context.state.emoji) + } + .widgetURL(URL(string: "http://www.apple.com")) + .keylineTint(Color.red) + } + } } extension vittywidgetAttributes { - fileprivate static var preview: vittywidgetAttributes { - vittywidgetAttributes(name: "World") - } + fileprivate static var preview: vittywidgetAttributes { + vittywidgetAttributes(name: "World") + } } extension vittywidgetAttributes.ContentState { - fileprivate static var smiley: vittywidgetAttributes.ContentState { - vittywidgetAttributes.ContentState(emoji: "😀") - } - - fileprivate static var starEyes: vittywidgetAttributes.ContentState { - vittywidgetAttributes.ContentState(emoji: "🤩") - } + fileprivate static var smiley: vittywidgetAttributes.ContentState { + vittywidgetAttributes.ContentState(emoji: "😀") + } + + fileprivate static var starEyes: vittywidgetAttributes.ContentState { + vittywidgetAttributes.ContentState(emoji: "🤩") + } } #Preview("Notification", as: .content, using: vittywidgetAttributes.preview) { - vittywidgetLiveActivity() + vittywidgetLiveActivity() } contentStates: { - vittywidgetAttributes.ContentState.smiley - vittywidgetAttributes.ContentState.starEyes + vittywidgetAttributes.ContentState.smiley + vittywidgetAttributes.ContentState.starEyes }