From c58f8ac07f99c2e5a40359a7d6e5cf7f2f6e359b Mon Sep 17 00:00:00 2001 From: Jevon Mao Date: Sat, 23 Apr 2022 13:35:48 -0700 Subject: [PATCH] App Store release v3.1.0 (#94) * Auto reload schedule in today view * Move order of setup remote config up * Readd deleted getSchedule code during merge * Add reload interval values to remote config * Reformat code * Fixed bug of schedule failing to update itself * Clean up warnings * fixed #93 * Fixed #92; Period 8 incorrectly show on holidays --- SMHS.xcodeproj/project.pbxproj | 122 +++++++++--------- Sources/SMHS (iOS)/AppCycle/AppDelegate.swift | 6 +- .../Components/TodayView/TodayHeroView.swift | 2 +- .../Views/TodayView/TodayView.swift | 3 +- Sources/Shared/Models/Endpoint.swift | 24 ++++ Sources/Shared/Models/GlobalObjects.swift | 27 ++++ .../Shared/Models/NetworkLoadViewModel.swift | 4 +- .../Models/SharedScheduleInformation.swift | 40 +++--- Sources/Shared/Utility/Extensions/Array.swift | 7 + Sources/Shared/Utility/Extensions/Date.swift | 9 +- .../Keychain/KeychainAccessibility.swift | 2 - .../Model/JSON/GradesSupplementSummary.swift | 4 +- .../ViewModel/GradesDetailViewModel.swift | 14 +- .../ViewModel/GradesViewModel.swift | 2 +- .../Model/PeriodParseExtensions.swift | 3 + .../ScheduleView/Model/ScheduleDay.swift | 22 +++- .../ScheduleView/Model/ScheduleWeek.swift | 4 +- .../ViewModels/ScheduleDateHelper.swift | 8 +- 18 files changed, 196 insertions(+), 107 deletions(-) diff --git a/SMHS.xcodeproj/project.pbxproj b/SMHS.xcodeproj/project.pbxproj index fa110c0..83a4b49 100644 --- a/SMHS.xcodeproj/project.pbxproj +++ b/SMHS.xcodeproj/project.pbxproj @@ -7,6 +7,29 @@ objects = { /* Begin PBXBuildFile section */ + 6201D9E42810C89B00EBC375 /* GradesSupplementSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9DD2810C89B00EBC375 /* GradesSupplementSummary.swift */; }; + 6201D9E52810C89B00EBC375 /* GradesSupplementSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9DD2810C89B00EBC375 /* GradesSupplementSummary.swift */; }; + 6201D9E62810C89B00EBC375 /* GradesSupplementSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9DD2810C89B00EBC375 /* GradesSupplementSummary.swift */; }; + 6201D9E72810C89B00EBC375 /* GradesRubric.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9DE2810C89B00EBC375 /* GradesRubric.swift */; }; + 6201D9E82810C89B00EBC375 /* GradesRubric.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9DE2810C89B00EBC375 /* GradesRubric.swift */; }; + 6201D9E92810C89B00EBC375 /* GradesRubric.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9DE2810C89B00EBC375 /* GradesRubric.swift */; }; + 6201D9EA2810C89B00EBC375 /* GradesDetailedRawResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9DF2810C89B00EBC375 /* GradesDetailedRawResponse.swift */; }; + 6201D9EB2810C89B00EBC375 /* GradesDetailedRawResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9DF2810C89B00EBC375 /* GradesDetailedRawResponse.swift */; }; + 6201D9EC2810C89B00EBC375 /* GradesDetailedRawResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9DF2810C89B00EBC375 /* GradesDetailedRawResponse.swift */; }; + 6201D9ED2810C89B00EBC375 /* GradesRubricRawResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9E02810C89B00EBC375 /* GradesRubricRawResponse.swift */; }; + 6201D9EE2810C89B00EBC375 /* GradesRubricRawResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9E02810C89B00EBC375 /* GradesRubricRawResponse.swift */; }; + 6201D9EF2810C89B00EBC375 /* GradesRubricRawResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9E02810C89B00EBC375 /* GradesRubricRawResponse.swift */; }; + 6201D9F02810C89B00EBC375 /* CourseGrade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9E12810C89B00EBC375 /* CourseGrade.swift */; }; + 6201D9F12810C89B00EBC375 /* CourseGrade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9E12810C89B00EBC375 /* CourseGrade.swift */; }; + 6201D9F22810C89B00EBC375 /* CourseGrade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9E12810C89B00EBC375 /* CourseGrade.swift */; }; + 6201D9F32810C89B00EBC375 /* GradesDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9E22810C89B00EBC375 /* GradesDetail.swift */; }; + 6201D9F42810C89B00EBC375 /* GradesDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9E22810C89B00EBC375 /* GradesDetail.swift */; }; + 6201D9F52810C89B00EBC375 /* GradesDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9E22810C89B00EBC375 /* GradesDetail.swift */; }; + 6201D9F62810C89B00EBC375 /* GradesSummaryRawResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9E32810C89B00EBC375 /* GradesSummaryRawResponse.swift */; }; + 6201D9F72810C89B00EBC375 /* GradesSummaryRawResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9E32810C89B00EBC375 /* GradesSummaryRawResponse.swift */; }; + 6201D9F82810C89B00EBC375 /* GradesSummaryRawResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6201D9E32810C89B00EBC375 /* GradesSummaryRawResponse.swift */; }; + 6201D9F92810C99600EBC375 /* Calendar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6211915E27EEF144008BD312 /* Calendar.swift */; }; + 6201D9FA2810C99700EBC375 /* Calendar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6211915E27EEF144008BD312 /* Calendar.swift */; }; 62102F81271A4A7900C81F68 /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = 6261DF2627121E42009F6234 /* FirebaseMessaging */; }; 62102F84271B74D100C81F68 /* GradesDetailRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62102F83271B74D100C81F68 /* GradesDetailRow.swift */; }; 6211915F27EEF144008BD312 /* Calendar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6211915E27EEF144008BD312 /* Calendar.swift */; }; @@ -40,16 +63,7 @@ 623A7F23264F595400FF3F28 /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 623A7F22264F595400FF3F28 /* SafariView.swift */; }; 623D595526FAF3C4001D05F7 /* GradesDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 623D595426FAF3C4001D05F7 /* GradesDetailView.swift */; }; 623D595726FAF3D9001D05F7 /* GradesDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 623D595626FAF3D9001D05F7 /* GradesDetailViewModel.swift */; }; - 623D595926FDA056001D05F7 /* GradesDetailedRawResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 623D595826FDA056001D05F7 /* GradesDetailedRawResponse.swift */; }; - 623D595B26FDA06F001D05F7 /* GradesDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 623D595A26FDA06F001D05F7 /* GradesDetail.swift */; }; - 623D595C26FDA06F001D05F7 /* GradesDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 623D595A26FDA06F001D05F7 /* GradesDetail.swift */; }; - 623D595D26FDA06F001D05F7 /* GradesDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 623D595A26FDA06F001D05F7 /* GradesDetail.swift */; }; - 623D595F26FDA075001D05F7 /* GradesDetailedRawResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 623D595826FDA056001D05F7 /* GradesDetailedRawResponse.swift */; }; - 623D596126FDA650001D05F7 /* GradesDetailedRawResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 623D595826FDA056001D05F7 /* GradesDetailedRawResponse.swift */; }; 623D596426FFCFC1001D05F7 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 623D596326FFCFC1001D05F7 /* Alamofire */; }; - 623D59662701944F001D05F7 /* GradesSupplementSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 623D59652701944F001D05F7 /* GradesSupplementSummary.swift */; }; - 623D59672701944F001D05F7 /* GradesSupplementSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 623D59652701944F001D05F7 /* GradesSupplementSummary.swift */; }; - 623D59682701944F001D05F7 /* GradesSupplementSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 623D59652701944F001D05F7 /* GradesSupplementSummary.swift */; }; 623D596B27024D43001D05F7 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 623D596A27024D43001D05F7 /* Kingfisher */; }; 624ABFF326004949000FE7BD /* Miscellaneous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 624ABFF226004949000FE7BD /* Miscellaneous.swift */; }; 624B06DC26D3521B001C2EAE /* FirebaseAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 624B06DB26D3521B001C2EAE /* FirebaseAnalytics */; }; @@ -287,24 +301,10 @@ 62F43CC02688F2AA0009CD34 /* GradesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62F43CBF2688F2AA0009CD34 /* GradesView.swift */; }; 62F43CC22688F3440009CD34 /* GradesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62F43CC12688F3440009CD34 /* GradesViewModel.swift */; }; 62F43CC42688F3780009CD34 /* GradesNetworkModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62F43CC32688F3780009CD34 /* GradesNetworkModel.swift */; }; - 62F43CC8268902380009CD34 /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62F43CC7268902380009CD34 /* Endpoint.swift */; }; - 62F43CCC2689028A0009CD34 /* GradesSummaryRawResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62F43CCB2689028A0009CD34 /* GradesSummaryRawResponse.swift */; }; - 62F43CCC2689028A0009CD34 /* GradesResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62F43CCB2689028A0009CD34 /* GradesResponse.swift */; }; 62F5FCFF26B4876600E821D5 /* LoadingAnimatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62F5FCFE26B4876600E821D5 /* LoadingAnimatable.swift */; }; 62F5FD0126B49A2D00E821D5 /* Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62F5FD0026B49A2D00E821D5 /* Font.swift */; }; 62F5FD0226B49B8B00E821D5 /* Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62F5FD0026B49A2D00E821D5 /* Font.swift */; }; 62F5FD0326B49B8C00E821D5 /* Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62F5FD0026B49A2D00E821D5 /* Font.swift */; }; - 62FE7F2727515D3C0015889C /* CourseGrade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FE7F2627515D3C0015889C /* CourseGrade.swift */; }; - 62FE7F2827515D3C0015889C /* CourseGrade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FE7F2627515D3C0015889C /* CourseGrade.swift */; }; - 62FE7F2927515D3C0015889C /* CourseGrade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FE7F2627515D3C0015889C /* CourseGrade.swift */; }; - 62FE7F2B27515DE30015889C /* GradesRubricRawResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FE7F2A27515DE30015889C /* GradesRubricRawResponse.swift */; }; - 62FE7F2C27515DE30015889C /* GradesRubricRawResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FE7F2A27515DE30015889C /* GradesRubricRawResponse.swift */; }; - 62FE7F2D27515DE30015889C /* GradesRubricRawResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FE7F2A27515DE30015889C /* GradesRubricRawResponse.swift */; }; - 62FE7F2F275161240015889C /* GradesRubric.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FE7F2E275161240015889C /* GradesRubric.swift */; }; - 62FE7F30275161240015889C /* GradesRubric.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FE7F2E275161240015889C /* GradesRubric.swift */; }; - 62FE7F31275161240015889C /* GradesRubric.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FE7F2E275161240015889C /* GradesRubric.swift */; }; - 62FE7F32275162600015889C /* GradesSummaryRawResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62F43CCB2689028A0009CD34 /* GradesSummaryRawResponse.swift */; }; - 62FE7F33275162610015889C /* GradesSummaryRawResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62F43CCB2689028A0009CD34 /* GradesSummaryRawResponse.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -346,6 +346,13 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 6201D9DD2810C89B00EBC375 /* GradesSupplementSummary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradesSupplementSummary.swift; sourceTree = ""; }; + 6201D9DE2810C89B00EBC375 /* GradesRubric.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradesRubric.swift; sourceTree = ""; }; + 6201D9DF2810C89B00EBC375 /* GradesDetailedRawResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradesDetailedRawResponse.swift; sourceTree = ""; }; + 6201D9E02810C89B00EBC375 /* GradesRubricRawResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradesRubricRawResponse.swift; sourceTree = ""; }; + 6201D9E12810C89B00EBC375 /* CourseGrade.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CourseGrade.swift; sourceTree = ""; }; + 6201D9E22810C89B00EBC375 /* GradesDetail.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradesDetail.swift; sourceTree = ""; }; + 6201D9E32810C89B00EBC375 /* GradesSummaryRawResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradesSummaryRawResponse.swift; sourceTree = ""; }; 62102F83271B74D100C81F68 /* GradesDetailRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradesDetailRow.swift; sourceTree = ""; }; 6211915E27EEF144008BD312 /* Calendar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Calendar.swift; sourceTree = ""; }; 621385EE265C60D500F4806C /* InformationCardItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InformationCardItem.swift; sourceTree = ""; }; @@ -370,9 +377,6 @@ 623A7F22264F595400FF3F28 /* SafariView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariView.swift; sourceTree = ""; }; 623D595426FAF3C4001D05F7 /* GradesDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradesDetailView.swift; sourceTree = ""; }; 623D595626FAF3D9001D05F7 /* GradesDetailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradesDetailViewModel.swift; sourceTree = ""; }; - 623D595826FDA056001D05F7 /* GradesDetailedRawResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradesDetailedRawResponse.swift; sourceTree = ""; }; - 623D595A26FDA06F001D05F7 /* GradesDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradesDetail.swift; sourceTree = ""; }; - 623D59652701944F001D05F7 /* GradesSupplementSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradesSupplementSummary.swift; sourceTree = ""; }; 624ABFF226004949000FE7BD /* Miscellaneous.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Miscellaneous.swift; sourceTree = ""; }; 624D5F522793DFA80037F1BF /* Endpoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Endpoint.swift; sourceTree = ""; }; 624F79EC264F875900B93C63 /* InformationCardsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InformationCardsView.swift; sourceTree = ""; }; @@ -499,13 +503,8 @@ 62F43CC12688F3440009CD34 /* GradesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradesViewModel.swift; sourceTree = ""; }; 62F43CC32688F3780009CD34 /* GradesNetworkModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradesNetworkModel.swift; sourceTree = ""; }; 62F43CC7268902380009CD34 /* Endpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Endpoint.swift; sourceTree = ""; }; - 62F43CCB2689028A0009CD34 /* GradesSummaryRawResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradesSummaryRawResponse.swift; sourceTree = ""; }; - 62F43CCB2689028A0009CD34 /* GradesResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradesResponse.swift; sourceTree = ""; }; 62F5FCFE26B4876600E821D5 /* LoadingAnimatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingAnimatable.swift; sourceTree = ""; }; 62F5FD0026B49A2D00E821D5 /* Font.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Font.swift; sourceTree = ""; }; - 62FE7F2627515D3C0015889C /* CourseGrade.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseGrade.swift; sourceTree = ""; }; - 62FE7F2A27515DE30015889C /* GradesRubricRawResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradesRubricRawResponse.swift; sourceTree = ""; }; - 62FE7F2E275161240015889C /* GradesRubric.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradesRubric.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1202,7 +1201,6 @@ children = ( 62FE7F2427515CD70015889C /* JSON */, 62F43CC32688F3780009CD34 /* GradesNetworkModel.swift */, - 62F43CCB2689028A0009CD34 /* GradesResponse.swift */, 625F189E268A9256000B71B4 /* RequestError.swift */, ); path = Model; @@ -1211,13 +1209,13 @@ 62FE7F2427515CD70015889C /* JSON */ = { isa = PBXGroup; children = ( - 62F43CCB2689028A0009CD34 /* GradesSummaryRawResponse.swift */, - 62FE7F2627515D3C0015889C /* CourseGrade.swift */, - 623D595826FDA056001D05F7 /* GradesDetailedRawResponse.swift */, - 623D595A26FDA06F001D05F7 /* GradesDetail.swift */, - 623D59652701944F001D05F7 /* GradesSupplementSummary.swift */, - 62FE7F2A27515DE30015889C /* GradesRubricRawResponse.swift */, - 62FE7F2E275161240015889C /* GradesRubric.swift */, + 6201D9E12810C89B00EBC375 /* CourseGrade.swift */, + 6201D9E22810C89B00EBC375 /* GradesDetail.swift */, + 6201D9DF2810C89B00EBC375 /* GradesDetailedRawResponse.swift */, + 6201D9DE2810C89B00EBC375 /* GradesRubric.swift */, + 6201D9E02810C89B00EBC375 /* GradesRubricRawResponse.swift */, + 6201D9E32810C89B00EBC375 /* GradesSummaryRawResponse.swift */, + 6201D9DD2810C89B00EBC375 /* GradesSupplementSummary.swift */, ); path = JSON; sourceTree = ""; @@ -1514,30 +1512,24 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 62FE7F2827515D3C0015889C /* CourseGrade.swift in Sources */, 62F30D012649A64C008EDD31 /* PeriodCategory.swift in Sources */, 624D5F572793DFD40037F1BF /* Dictionary.swift in Sources */, 62B227CD265D61A10023A7E6 /* SMStretchyHeader.swift in Sources */, 62CFAA3D264756ED003B2EA0 /* DateFormatter.swift in Sources */, - 623D595B26FDA06F001D05F7 /* GradesDetail.swift in Sources */, 6261841026371A92001C4AD4 /* ScheduleDay.swift in Sources */, 62C9E8A4263D13CB00CCA5C5 /* HighlightButtonStyle.swift in Sources */, 62E05F6D2639C4AC00B609E3 /* SettingsView.swift in Sources */, 6261841126371A92001C4AD4 /* ScheduleWeek.swift in Sources */, - 6211916027EEF144008BD312 /* Calendar.swift in Sources */, 62F5FD0326B49B8C00E821D5 /* Font.swift in Sources */, - 62FE7F30275161240015889C /* GradesRubric.swift in Sources */, - 62FE7F2C27515DE30015889C /* GradesRubricRawResponse.swift in Sources */, - 623D59662701944F001D05F7 /* GradesSupplementSummary.swift in Sources */, 62D1E50B263DD712004DBFAD /* ScheduleDateHelper.swift in Sources */, 62B227C1265CC1D20023A7E6 /* WhyStatementView.swift in Sources */, 62B227C9265CD06E0023A7E6 /* AboutDevView.swift in Sources */, 62E3BF002642583100E1FF88 /* UIElementPreview.swift in Sources */, 62E2E091268598AA009608FB /* NetworkLoadViewModel.swift in Sources */, + 6201D9EE2810C89B00EBC375 /* GradesRubricRawResponse.swift in Sources */, 62B0D9652692638700AA6CF4 /* KeychainWrapper.swift in Sources */, 6261841526371A93001C4AD4 /* ScheduleView.swift in Sources */, 6261841626371A93001C4AD4 /* SharedScheduleInformation.swift in Sources */, - 62FE7F33275162610015889C /* GradesSummaryRawResponse.swift in Sources */, 62CFAA41264756F9003B2EA0 /* TimeInterval.swift in Sources */, 62D1E54E263DFD46004DBFAD /* ScheduleViewTextLines.swift in Sources */, 62626395264DD21D004146CE /* PeriodEditItem.swift in Sources */, @@ -1549,19 +1541,23 @@ 62C9E89C263D0D9600CCA5C5 /* OnboardingView.swift in Sources */, 627752F92665FC8F000BAD0B /* HeaderOverlayLabel.swift in Sources */, 62626392264DCFA0004146CE /* PeriodEditSettingsView.swift in Sources */, + 6201D9EB2810C89B00EBC375 /* GradesDetailedRawResponse.swift in Sources */, 6261840626371A6C001C4AD4 /* Miscellaneous.swift in Sources */, 622EEF872751CB71009C1D1C /* Double.swift in Sources */, 62D1E508263DD41C004DBFAD /* Date.swift in Sources */, 62B0D96B2692776200AA6CF4 /* ActionButton.swift in Sources */, 6261840726371A6C001C4AD4 /* String.swift in Sources */, 62E05F712639C5D000B609E3 /* UserSettings.swift in Sources */, - 623D595F26FDA075001D05F7 /* GradesDetailedRawResponse.swift in Sources */, 62B227C5265CC1E00023A7E6 /* HowStatementView.swift in Sources */, 62E05F6B2639C47C00B609E3 /* ContentView.swift in Sources */, + 6201D9E82810C89B00EBC375 /* GradesRubric.swift in Sources */, 62B227BC265CBE530023A7E6 /* Acknowledgements.swift in Sources */, + 6201D9F42810C89B00EBC375 /* GradesDetail.swift in Sources */, 62B0D9672692638A00AA6CF4 /* KeychainAccessibility.swift in Sources */, 62D32121264A4C6700C99C42 /* ClassPeriod.swift in Sources */, 6261840826371A6C001C4AD4 /* Colors.swift in Sources */, + 6201D9F12810C89B00EBC375 /* CourseGrade.swift in Sources */, + 6201D9E52810C89B00EBC375 /* GradesSupplementSummary.swift in Sources */, 62C9E8B1263D212E00CCA5C5 /* Bindings.swift in Sources */, 624D5F542793DFA80037F1BF /* Endpoint.swift in Sources */, 62B227D1265D63270023A7E6 /* SocialMediaIcons.swift in Sources */, @@ -1579,11 +1575,13 @@ 6261840A26371A6C001C4AD4 /* Array.swift in Sources */, 62C9E8AE263D1DBE00CCA5C5 /* AppVersionStatus.swift in Sources */, 62D321032649D8D700C99C42 /* NewsView.swift in Sources */, + 6201D9F72810C89B00EBC375 /* GradesSummaryRawResponse.swift in Sources */, 6261840B26371A6C001C4AD4 /* MockScheduleView.swift in Sources */, 62E05F6626391CFA00B609E3 /* ScheduleListHeaderView.swift in Sources */, 62353A522638894500207C15 /* ScheduleListView.swift in Sources */, 626184232637384E001C4AD4 /* RoundedCorners.swift in Sources */, 626183A72637168D001C4AD4 /* SMHSSchedule__macOS_App.swift in Sources */, + 6201D9FA2810C99700EBC375 /* Calendar.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1599,7 +1597,6 @@ 62D8737826BE19B9003DE95B /* UIDevice.swift in Sources */, 62C9E8A1263D110100CCA5C5 /* OnboardingRowItem.swift in Sources */, 62A11A9326F9A2A0007F7241 /* OnboardingRowItemLegacy.swift in Sources */, - 623D59672701944F001D05F7 /* GradesSupplementSummary.swift in Sources */, 627752F72665FC87000BAD0B /* HeaderOverlayLabel.swift in Sources */, 62D1E54F263DFD46004DBFAD /* ScheduleViewTextLines.swift in Sources */, 626183E9263718E0001C4AD4 /* String.swift in Sources */, @@ -1615,7 +1612,6 @@ 629EC8352645D50900E236DC /* TodayViewViewModel.swift in Sources */, 621F5CA3266AAB0F006EBE8F /* CalendarEvent.swift in Sources */, 629BE8BB2636430A00BC49AD /* MockScheduleView.swift in Sources */, - 62F43CCC2689028A0009CD34 /* GradesSummaryRawResponse.swift in Sources */, 6287EA672654D6D3007B41CB /* ScheduleListHeaderText.swift in Sources */, 626A229F260039BC00903C39 /* Colors.swift in Sources */, 62C48DAB265C6CA70032301E /* FooterModalView.swift in Sources */, @@ -1624,16 +1620,17 @@ 621F5CA7266ACF05006EBE8F /* SelectedDateView.swift in Sources */, 62B0D969269263A800AA6CF4 /* KeychainPublishedWrapper.swift in Sources */, 621F5C8B2669F7FF006EBE8F /* SMHSInformation.swift in Sources */, + 6201D9F02810C89B00EBC375 /* CourseGrade.swift in Sources */, 62C48DB0265C7A6D0032301E /* SocialMediaLinks.swift in Sources */, 623D595726FAF3D9001D05F7 /* GradesDetailViewModel.swift in Sources */, 62B227DA265D9A430023A7E6 /* FeaturesStatementView.swift in Sources */, + 6201D9E72810C89B00EBC375 /* GradesRubric.swift in Sources */, 62626390264DC5E3004146CE /* DeveloperSettingsView.swift in Sources */, 624F79F4264FA13500B93C63 /* NewsSelectionButtons.swift in Sources */, 625F189F268A9256000B71B4 /* RequestError.swift in Sources */, 623D595526FAF3C4001D05F7 /* GradesDetailView.swift in Sources */, 6279EAD02630F6EE00CF3870 /* UIScreen.swift in Sources */, 62B227BD265CBE530023A7E6 /* Acknowledgements.swift in Sources */, - 623D595C26FDA06F001D05F7 /* GradesDetail.swift in Sources */, 62B227CE265D61A10023A7E6 /* SMStretchyHeader.swift in Sources */, 62B0D961269260FB00AA6CF4 /* KeychainWrapper.swift in Sources */, 62382B5526E6994D00BF8918 /* AnnoucementBanner.swift in Sources */, @@ -1646,7 +1643,6 @@ 624ABFF326004949000FE7BD /* Miscellaneous.swift in Sources */, 62B227E0265DAE4C0023A7E6 /* AboutFooterView.swift in Sources */, 62B227D2265D63270023A7E6 /* SocialMediaIcons.swift in Sources */, - 62FE7F2F275161240015889C /* GradesRubric.swift in Sources */, 62C9E8B2263D212E00CCA5C5 /* Bindings.swift in Sources */, 626A22992600381700903C39 /* ScheduleView.swift in Sources */, 62C9E898263D0AB700CCA5C5 /* OnboardingWrapperView.swift in Sources */, @@ -1657,21 +1653,22 @@ 62DE61EC2602525400B86555 /* SharedScheduleInformation.swift in Sources */, 621F5CA5266AAB35006EBE8F /* CalendarManager.swift in Sources */, 62E05F722639C5D000B609E3 /* UserSettings.swift in Sources */, + 6201D9F32810C89B00EBC375 /* GradesDetail.swift in Sources */, 62D8CB7F26E2D136004DD19B /* TodayNetworkModel.swift in Sources */, 62F43CC22688F3440009CD34 /* GradesViewModel.swift in Sources */, 62D1E50C263DD712004DBFAD /* ScheduleDateHelper.swift in Sources */, 62D1E509263DD41C004DBFAD /* Date.swift in Sources */, + 6201D9F62810C89B00EBC375 /* GradesSummaryRawResponse.swift in Sources */, 62C48DB3265CA88A0032301E /* SocialDetailView.swift in Sources */, 621F5C872669F368006EBE8F /* InternetErrorView.swift in Sources */, 6255035B271A42A00090F62A /* SMHSApp.swift in Sources */, 62E05F6726391CFA00B609E3 /* ScheduleListHeaderView.swift in Sources */, 626A2296260037E800903C39 /* TodayView.swift in Sources */, + 6201D9E42810C89B00EBC375 /* GradesSupplementSummary.swift in Sources */, 62CFAA3E264756ED003B2EA0 /* DateFormatter.swift in Sources */, - 623D595926FDA056001D05F7 /* GradesDetailedRawResponse.swift in Sources */, 62B227D6265D82C40023A7E6 /* WKWebViewRepresentable.swift in Sources */, 62763AA3264A6DEE006162EA /* ProgressCountdown.swift in Sources */, 624F7A002651A4E600B93C63 /* HapticsManager.swift in Sources */, - 62FE7F2727515D3C0015889C /* CourseGrade.swift in Sources */, 6287EA6A26558081007B41CB /* CustomScheduleView.swift in Sources */, 62D3211C2649F2BD00C99C42 /* NewsDetailedView.swift in Sources */, 62D32122264A4C6700C99C42 /* ClassPeriod.swift in Sources */, @@ -1704,10 +1701,11 @@ 625F18A2268A984B000B71B4 /* CourseGradeItem.swift in Sources */, 62863BAE26AF461100084C28 /* Dictionary.swift in Sources */, 62863BAC26AF3DFB00084C28 /* LoginButton.swift in Sources */, - 62FE7F2B27515DE30015889C /* GradesRubricRawResponse.swift in Sources */, 626184242637384E001C4AD4 /* RoundedCorners.swift in Sources */, + 6201D9ED2810C89B00EBC375 /* GradesRubricRawResponse.swift in Sources */, 62B0D9632692611500AA6CF4 /* KeychainAccessibility.swift in Sources */, 62A11A8026E6CBDE007F7241 /* GlobalObjects.swift in Sources */, + 6201D9EA2810C89B00EBC375 /* GradesDetailedRawResponse.swift in Sources */, 62F43CC42688F3780009CD34 /* GradesNetworkModel.swift in Sources */, 626A2269260035F100903C39 /* AppDelegate.swift in Sources */, 6287EA6426548BC6007B41CB /* ScheduleListBanner.swift in Sources */, @@ -1745,57 +1743,57 @@ 62CFAA43264756F9003B2EA0 /* TimeInterval.swift in Sources */, 62D1E550263DFD46004DBFAD /* ScheduleViewTextLines.swift in Sources */, 62D8CB8326E42280004DD19B /* ScheduleDay.swift in Sources */, + 6201D9F22810C89B00EBC375 /* CourseGrade.swift in Sources */, 62E3BF022642583100E1FF88 /* UIElementPreview.swift in Sources */, 624D5F552793DFA80037F1BF /* Endpoint.swift in Sources */, 62D1E52D263DF859004DBFAD /* UserSettings.swift in Sources */, + 6201D9EC2810C89B00EBC375 /* GradesDetailedRawResponse.swift in Sources */, 62D1E52E263DF859004DBFAD /* SettingsView.swift in Sources */, 62D1E530263DF859004DBFAD /* AppVersionStatus.swift in Sources */, 62D1E532263DF859004DBFAD /* OnboardingRowItem.swift in Sources */, 6287EA682654D776007B41CB /* ScheduleListHeaderText.swift in Sources */, - 623D595D26FDA06F001D05F7 /* GradesDetail.swift in Sources */, 62E2E093268598AA009608FB /* NetworkLoadViewModel.swift in Sources */, 62D1E537263DF859004DBFAD /* ScheduleListHeaderView.swift in Sources */, 62D1E538263DF859004DBFAD /* UserDefaultWrapper.swift in Sources */, + 6201D9F82810C89B00EBC375 /* GradesSummaryRawResponse.swift in Sources */, 62D1E53A263DF859004DBFAD /* Miscellaneous.swift in Sources */, 62B227C3265CC1D60023A7E6 /* WhyStatementView.swift in Sources */, - 62FE7F2927515D3C0015889C /* CourseGrade.swift in Sources */, 62D8CB8526E422B6004DD19B /* PeriodParseExtensions.swift in Sources */, - 623D596126FDA650001D05F7 /* GradesDetailedRawResponse.swift in Sources */, 621F5C99266A9830006EBE8F /* HapticsManager.swift in Sources */, 62F5FD0226B49B8B00E821D5 /* Font.swift in Sources */, 62B0D96D2692776200AA6CF4 /* ActionButton.swift in Sources */, 624D5F562793DFD20037F1BF /* Dictionary.swift in Sources */, + 6201D9F92810C99600EBC375 /* Calendar.swift in Sources */, 6287EA7226577D05007B41CB /* PeriodBlockItem.swift in Sources */, 62B227C7265CC1E00023A7E6 /* HowStatementView.swift in Sources */, 62B227DF265DADC70023A7E6 /* PeriodBlockSubview.swift in Sources */, 62D1E53B263DF859004DBFAD /* RoundedCorners.swift in Sources */, 62A11A8126E6CBDE007F7241 /* GlobalObjects.swift in Sources */, + 6201D9E92810C89B00EBC375 /* GradesRubric.swift in Sources */, 62D1E53D263DF859004DBFAD /* Bindings.swift in Sources */, 62B227BF265CC03A0023A7E6 /* Acknowledgements.swift in Sources */, 6287EA6526548DCF007B41CB /* ScheduleListBanner.swift in Sources */, 62D1E53E263DF859004DBFAD /* String.swift in Sources */, 62D1E53F263DF859004DBFAD /* Colors.swift in Sources */, - 6211916127EEF144008BD312 /* Calendar.swift in Sources */, 62B227D7265D82C40023A7E6 /* WKWebViewRepresentable.swift in Sources */, 62CFAA3F264756ED003B2EA0 /* DateFormatter.swift in Sources */, 62D1E541263DF859004DBFAD /* Array.swift in Sources */, 627752FA266603B8000BAD0B /* UIScreen.swift in Sources */, 621F5C892669F58D006EBE8F /* LoadingIndicatorView.swift in Sources */, 6287EA6E265587C1007B41CB /* CustomScheduleView.swift in Sources */, - 623D59682701944F001D05F7 /* GradesSupplementSummary.swift in Sources */, 62D1E523263DF7E5004DBFAD /* ScheduleDetailView.swift in Sources */, 62D1E526263DF833004DBFAD /* Date.swift in Sources */, 62A11A9426F9A2A0007F7241 /* OnboardingRowItemLegacy.swift in Sources */, 6287EA6F265587CD007B41CB /* ScheduleCustomViewModel.swift in Sources */, + 6201D9E62810C89B00EBC375 /* GradesSupplementSummary.swift in Sources */, 62D1E525263DF82B004DBFAD /* ScheduleWeek.swift in Sources */, - 62FE7F31275161240015889C /* GradesRubric.swift in Sources */, - 62FE7F2D27515DE30015889C /* GradesRubricRawResponse.swift in Sources */, 62D32123264A4C6700C99C42 /* ClassPeriod.swift in Sources */, + 6201D9EF2810C89B00EBC375 /* GradesRubricRawResponse.swift in Sources */, 62D1E518263DF778004DBFAD /* Widgets.swift in Sources */, - 62FE7F32275162600015889C /* GradesSummaryRawResponse.swift in Sources */, 62A11A8F26F9A0B4007F7241 /* OnboardingFeature.swift in Sources */, 622EEF882751CB71009C1D1C /* Double.swift in Sources */, 62B0D9642692638600AA6CF4 /* KeychainWrapper.swift in Sources */, + 6201D9F52810C89B00EBC375 /* GradesDetail.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Sources/SMHS (iOS)/AppCycle/AppDelegate.swift b/Sources/SMHS (iOS)/AppCycle/AppDelegate.swift index 2d40d54..148c236 100644 --- a/Sources/SMHS (iOS)/AppCycle/AppDelegate.swift +++ b/Sources/SMHS (iOS)/AppCycle/AppDelegate.swift @@ -15,10 +15,10 @@ final class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { // Configure Firebase Suite FirebaseApp.configure() + setupFirebaseRemoteConfig() setupPushNotifications() setupFirebaseMessaging() - setupFirebaseRemoteConfig() - + return true } @@ -53,7 +53,7 @@ extension AppDelegate: UNUserNotificationCenterDelegate { withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { // Change this to your preferred presentation option - completionHandler([[.alert, .banner, .sound]]) + completionHandler([.banner, .sound, .list]) } // Receive notification for when app is in foreground diff --git a/Sources/SMHS (iOS)/Views/TodayView/Components/TodayView/TodayHeroView.swift b/Sources/SMHS (iOS)/Views/TodayView/Components/TodayView/TodayHeroView.swift index f7a78e8..6510f21 100644 --- a/Sources/SMHS (iOS)/Views/TodayView/Components/TodayView/TodayHeroView.swift +++ b/Sources/SMHS (iOS)/Views/TodayView/Components/TodayView/TodayHeroView.swift @@ -93,7 +93,7 @@ struct TodayHeroView: View { struct TodayHeroView_Previews: PreviewProvider { static var previews: some View { - TodayView(networkLoadViewModel: NetworkLoadViewModel(dataReload: {_,_ in}), scheduleViewViewModel: .mockScheduleView, todayViewViewModel: .mockViewModel) + TodayView(networkLoadViewModel: NetworkLoadViewModel(dataReload: {_,_,_ in}), scheduleViewViewModel: .mockScheduleView, todayViewViewModel: .mockViewModel) .environmentObject(UserSettings()) } } diff --git a/Sources/SMHS (iOS)/Views/TodayView/TodayView.swift b/Sources/SMHS (iOS)/Views/TodayView/TodayView.swift index 3cb6ad5..3baca40 100644 --- a/Sources/SMHS (iOS)/Views/TodayView/TodayView.swift +++ b/Sources/SMHS (iOS)/Views/TodayView/TodayView.swift @@ -43,6 +43,7 @@ struct TodayView: View { UISegmentedControl.appearance().selectedSegmentTintColor = UIColor(appPrimary) UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected) UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor(appSecondary)], for: .normal) + scheduleViewViewModel.reloadData() } .onDisappear { todayViewViewModel.showNetworkError = true @@ -96,7 +97,7 @@ struct TodayViewHeader: View { struct TodayView_Previews: PreviewProvider { static var previews: some View { - TodayView(networkLoadViewModel: NetworkLoadViewModel(dataReload: {_,_ in }), + TodayView(networkLoadViewModel: NetworkLoadViewModel(dataReload: {_,_,_ in }), scheduleViewViewModel: SharedScheduleInformation()) .environmentObject(UserSettings()) } diff --git a/Sources/Shared/Models/Endpoint.swift b/Sources/Shared/Models/Endpoint.swift index 7d94710..f0c6740 100644 --- a/Sources/Shared/Models/Endpoint.swift +++ b/Sources/Shared/Models/Endpoint.swift @@ -44,6 +44,12 @@ extension Endpoint { request.httpBody = requestBody.percentEncoded() } } + let userAgent = AppVersionStatus.appDisplayName + + "/" + + AppVersionStatus.currentVersion! + + " " + + "Developer email/maoj@smhs.app" + request.setValue(userAgent, forHTTPHeaderField: "User-Agent") request.setValue("br;q=1.0, gzip;q=0.9, deflate;q=0.8", forHTTPHeaderField: "Accept-Encoding") if isApplicationJson { request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type") @@ -62,6 +68,9 @@ extension Endpoint { static let AERIES_API_LOGIN_PATH = "/parent/LoginParent.aspx" static let AERIES_API_ALT_GRADES_PATH = "/Parent/Widgets/ClassSummary/GetClassSummary" + static let APPSERV_API_HOST = "appserv.u360mobile.com" + static let APPSERV_API_SCHEDULE_PATH = "/354/calendarfeed.php" + static func studentLogin(email: String, password: String, debugMode: Bool = false) -> Endpoint { @@ -148,5 +157,20 @@ extension Endpoint { value: formatter.serverTimeFormat(date))], httpMethod: "GET") } + + static func getSchedule(date: Date) -> Endpoint { + let formatter = DateFormatter() + return Endpoint(host: APPSERV_API_HOST, + path: APPSERV_API_SCHEDULE_PATH, + queryItems: [.init(name: "i", value: "santamargaritahs"), + .init(name: "pageSize", value: "25"), + .init(name: "pageNumber", value: "1"), + .init(name: "dateStart", value: formatter.yearMonthDayFormat(date)), + .init(name: "categoryId", value: "0"), + .init(name: "tz", value: "America%2FLos_Angeles"), + .init(name: "mid", value: "1422"), + .init(name: "smid", value: "46492")], + httpMethod: "GET") + } } diff --git a/Sources/Shared/Models/GlobalObjects.swift b/Sources/Shared/Models/GlobalObjects.swift index 2990b28..235b330 100644 --- a/Sources/Shared/Models/GlobalObjects.swift +++ b/Sources/Shared/Models/GlobalObjects.swift @@ -38,4 +38,31 @@ extension RemoteConfig { return url } + + var RELOAD_INTERVAL_GRADE: TimeInterval { + #if DEBUG + 0 + #else + globalRemoteConfig.configValue(forKey: "reload_interval_grade").numberValue.doubleValue + #endif + } + + var RELOAD_INTERVAL_SCHEDULE: TimeInterval { + #if DEBUG + 0 + #else + globalRemoteConfig.configValue(forKey: "reload_interval_schedule").numberValue.doubleValue + #endif + } + + var NO_SCHOOL_IDENTIFIERS: [String] { + let data = globalRemoteConfig.configValue(forKey: "no_school_identifier").jsonValue + if let values = (data as? [String: [String]]), + let identifiers = values["contains"] { + return identifiers + } + else { + return ["SMCHS Events", "Holiday"] + } + } } diff --git a/Sources/Shared/Models/NetworkLoadViewModel.swift b/Sources/Shared/Models/NetworkLoadViewModel.swift index ab3cf5b..134b884 100644 --- a/Sources/Shared/Models/NetworkLoadViewModel.swift +++ b/Sources/Shared/Models/NetworkLoadViewModel.swift @@ -22,7 +22,7 @@ final class NetworkLoadViewModel: ObservableObject { lastStatus == .satisfied } - typealias Reloader = (Date, @escaping (Bool) -> Void) -> Void + typealias Reloader = (Date, Bool, @escaping (Bool) -> Void) -> Void var dataReload: Reloader init(dataReload: @escaping Reloader) { @@ -34,7 +34,7 @@ final class NetworkLoadViewModel: ObservableObject { func reloadDataNow() { //Show indicator while loading isLoading = true - dataReload(Date()) {success in + dataReload(Date(), true) {success in DispatchQueue.main.asyncAfter(deadline: .now()+0.2) { self.isLoading = false } diff --git a/Sources/Shared/Models/SharedScheduleInformation.swift b/Sources/Shared/Models/SharedScheduleInformation.swift index c2f12c3..7c9ae0b 100644 --- a/Sources/Shared/Models/SharedScheduleInformation.swift +++ b/Sources/Shared/Models/SharedScheduleInformation.swift @@ -55,7 +55,7 @@ final class SharedScheduleInformation: ObservableObject { self.urlString = urlString self.downloader = downloader print("Called fetch data from initializer...") - fetchData() + fetchData(purgeExisting: true) let shouldPurge = globalRemoteConfig.configValue(forKey: "purge_data_onupdate").boolValue // Purge all data when app update applied @@ -69,17 +69,16 @@ final class SharedScheduleInformation: ObservableObject { func reloadData() { if let time = lastReloadTime { // minimum reload interval is 6 hours - if abs(Date().timeIntervalSince(time)) > TimeInterval(21600) { + if abs(Date().timeIntervalSince(time)) > TimeInterval(globalRemoteConfig.RELOAD_INTERVAL_SCHEDULE) { print("Reload valid, fetching data") - fetchData() + fetchData(purgeExisting: true) lastReloadTime = Date() } - print("Reload invalid") } else { print("Reload 1st time, fetching data") lastReloadTime = Date() - fetchData() + fetchData(purgeExisting: true) } } @@ -93,6 +92,7 @@ final class SharedScheduleInformation: ObservableObject { // 2. smhs.org ICS calendar feed, used as a // redundency to fallback on if above fails func fetchData(startDate: Date = Date().startOfWeek(), + purgeExisting: Bool = false, completion: ((Bool) -> Void)? = nil) { // AppServ API let endpoint = Endpoint.getSchedule(date: startDate) @@ -102,11 +102,12 @@ final class SharedScheduleInformation: ObservableObject { if let data = response.data { let xml = XML.parse(data) - var scheduleDays = [(String, String)]() + var scheduleDays = [(date: String, schedule: String, title: String)]() for day in xml["CALENDAR", "EVENT"] { if let scheduleText = day["DESCRIPTION"].text, - let date = day["EVENTDATE"].text { - scheduleDays.append((date, scheduleText)) + let date = day["EVENTDATE"].text, + let title = day["TITLE"].text { + scheduleDays.append((date, scheduleText, title)) } } let formatter = DateFormatter() @@ -114,7 +115,13 @@ final class SharedScheduleInformation: ObservableObject { self?.minDate = formatter.serverTimeFormat(metadata["MINDATE"].text) self?.maxDate = formatter.serverTimeFormat(metadata["MAXDATE"].text) let fetchedSchedule = self?.dateHelper.parseScheduleXML(forDays: scheduleDays) - self?.scheduleWeeks.appendUnion(contentsOf: fetchedSchedule) + if purgeExisting { + self?.scheduleWeeks = fetchedSchedule ?? [] + } + else { + self?.scheduleWeeks.appendUnion(contentsOf: fetchedSchedule) + } + self?.isLoading = false #if DEBUG debugPrint("✅ Successfully fetched from main AppServ API.") @@ -186,23 +193,24 @@ final class SharedScheduleInformation: ObservableObject { ICSText = nil; scheduleWeeks = []; } + // Reloads the infinite scroll as needed func reloadScrollList(currentWeek: ScheduleWeek) { if currentWeek == scheduleWeeks.last { - guard let lastDay = scheduleWeeks.last?.scheduleDays.last?.date + guard let lastDay = scheduleWeeks.last?.scheduleDays.last?.date, + let minDate = minDate, + let maxDate = maxDate else { return } - guard let minDate = minDate, let maxDate = maxDate - else { + if (lastDay < maxDate && lastDay > minDate) + && scheduleWeeks.isNotLast(for: currentWeek){ + debugPrint("✅ Reloaded infinite scroll list successfully") fetchData(startDate: lastDay) return } - - if lastDay < maxDate && lastDay > minDate { - fetchData(startDate: lastDay) - } } + debugPrint("⚠️ reloadScrollList() called, but did not realod.") } } diff --git a/Sources/Shared/Utility/Extensions/Array.swift b/Sources/Shared/Utility/Extensions/Array.swift index 4d47623..1810bbb 100644 --- a/Sources/Shared/Utility/Extensions/Array.swift +++ b/Sources/Shared/Utility/Extensions/Array.swift @@ -50,4 +50,11 @@ extension Array { guard let newElements = newElements else {return} self.append(contentsOf: newElements.filter {!self.contains($0)}) } + + func isNotLast(for element: Self.Element) -> Bool where Element: Equatable { + if let index = self.firstIndex(of: element) { + return index < self.count - 1 + } + return true + } } diff --git a/Sources/Shared/Utility/Extensions/Date.swift b/Sources/Shared/Utility/Extensions/Date.swift index e0050bd..6814af0 100644 --- a/Sources/Shared/Utility/Extensions/Date.swift +++ b/Sources/Shared/Utility/Extensions/Date.swift @@ -8,10 +8,11 @@ import Foundation extension Date { - - static func currentWeekday(for date: Date = Date()) -> Int {Calendar.current.component(.weekday, from: date)-1} - - static func getDayOfTheWeek(for date: Date = Date()) -> Int {Calendar.iso8601.component(.weekday, from: date)-1} + + // 0 is Sunday, week starts on Monday (1), end on Saturday (6) + static func getDayOfTheWeek(for date: Date = Date()) -> Int { + Calendar.iso8601.component(.weekday, from: date) - 1 + } func isBetween(_ date1: Date, and date2: Date) -> Bool {(min(date1, date2) ... max(date1, date2)).contains(self)} diff --git a/Sources/Shared/Utility/Keychain/KeychainAccessibility.swift b/Sources/Shared/Utility/Keychain/KeychainAccessibility.swift index 85dc4e0..682bd5c 100644 --- a/Sources/Shared/Utility/Keychain/KeychainAccessibility.swift +++ b/Sources/Shared/Utility/Keychain/KeychainAccessibility.swift @@ -105,9 +105,7 @@ private let keychainItemAccessibilityLookup: [KeychainItemAccessibility:CFString var lookup: [KeychainItemAccessibility:CFString] = [ .afterFirstUnlock: kSecAttrAccessibleAfterFirstUnlock, .afterFirstUnlockThisDeviceOnly: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, - .always: kSecAttrAccessibleAlways, .whenPasscodeSetThisDeviceOnly: kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, - .alwaysThisDeviceOnly : kSecAttrAccessibleAlwaysThisDeviceOnly, .whenUnlocked: kSecAttrAccessibleWhenUnlocked, .whenUnlockedThisDeviceOnly: kSecAttrAccessibleWhenUnlockedThisDeviceOnly ] diff --git a/Sources/Shared/Views/GradesView/Model/JSON/GradesSupplementSummary.swift b/Sources/Shared/Views/GradesView/Model/JSON/GradesSupplementSummary.swift index 8fa0cac..32b57a2 100644 --- a/Sources/Shared/Views/GradesView/Model/JSON/GradesSupplementSummary.swift +++ b/Sources/Shared/Views/GradesView/Model/JSON/GradesSupplementSummary.swift @@ -108,9 +108,7 @@ class JSONNull: Codable, Hashable { return true } - public var hashValue: Int { - return 0 - } + func hash(into hasher: inout Hasher) {} public init() {} diff --git a/Sources/Shared/Views/GradesView/ViewModel/GradesDetailViewModel.swift b/Sources/Shared/Views/GradesView/ViewModel/GradesDetailViewModel.swift index 758c657..aa7f40e 100644 --- a/Sources/Shared/Views/GradesView/ViewModel/GradesDetailViewModel.swift +++ b/Sources/Shared/Views/GradesView/ViewModel/GradesDetailViewModel.swift @@ -128,11 +128,11 @@ class GradesDetailViewModel: ObservableObject { } func computeOverallPercentage(with gradesRubric: [GradesRubricRawResponse.Category]) -> Double { - var totalGrade = 0.0 - var totalWeight = 0.0 + var totalGrade: Double = 0.0 + var totalWeight: Double = 0.0 for category in gradesRubric { guard category.isDoingWeight else { continue } - let correctScore = self.detailedAssignments + let correctScore: Double = self.detailedAssignments .filter {$0.category == category.category} .filter {$0.dateCompleted != nil} .filter { @@ -144,7 +144,7 @@ class GradesDetailViewModel: ObservableObject { .map {$0.numberCorrect} .reduce(0, {$0 + $1}) - let possibleScore = self.detailedAssignments + let possibleScore: Double = self.detailedAssignments .filter {$0.category == category.category} .filter {$0.dateCompleted != nil} .filter { @@ -157,13 +157,13 @@ class GradesDetailViewModel: ObservableObject { .reduce(0, {$0 + $1}) //guard let _assignments = assignments else { return } - let weight = Double(category.percentOfGrade) / 100 + let weight: Double = Double(category.percentOfGrade) / 100 if possibleScore > 0 { - totalGrade += (correctScore / possibleScore) * weight + totalGrade += (correctScore / possibleScore) * weight totalWeight += weight } } - let percent = (totalGrade / totalWeight) * 100 + let percent: Double = (totalGrade / totalWeight) * 100 return percent.truncate(places: 2) } } diff --git a/Sources/Shared/Views/GradesView/ViewModel/GradesViewModel.swift b/Sources/Shared/Views/GradesView/ViewModel/GradesViewModel.swift index 8cb6180..951ba28 100644 --- a/Sources/Shared/Views/GradesView/ViewModel/GradesViewModel.swift +++ b/Sources/Shared/Views/GradesView/ViewModel/GradesViewModel.swift @@ -129,7 +129,7 @@ extension GradesViewModel { loginAndFetch() #else if let time = lastReloadTime { - if abs(Date().timeIntervalSince(time)) > TimeInterval(60 * 10) { + if abs(Date().timeIntervalSince(time)) > TimeInterval(globalRemoteConfig.RELOAD_INTERVAL_GRADE) { loginAndFetch() lastReloadTime = Date() } diff --git a/Sources/Shared/Views/ScheduleView/Model/PeriodParseExtensions.swift b/Sources/Shared/Views/ScheduleView/Model/PeriodParseExtensions.swift index 94415bb..3842786 100644 --- a/Sources/Shared/Views/ScheduleView/Model/PeriodParseExtensions.swift +++ b/Sources/Shared/Views/ScheduleView/Model/PeriodParseExtensions.swift @@ -168,6 +168,9 @@ extension ScheduleDay { guard p8DayIntArray.contains(Double(self.dayOfTheWeek)) else { return periods } + guard !globalRemoteConfig.NO_SCHOOL_IDENTIFIERS.contains(dayTitle ?? "") + else {return periods} + //Get periods's start and end times from remote config let timesConfig = globalRemoteConfig.configValue(forKey: "period_eight_time").jsonValue guard let times = timesConfig as? [String: String] diff --git a/Sources/Shared/Views/ScheduleView/Model/ScheduleDay.swift b/Sources/Shared/Views/ScheduleView/Model/ScheduleDay.swift index ef78779..4995bb3 100644 --- a/Sources/Shared/Views/ScheduleView/Model/ScheduleDay.swift +++ b/Sources/Shared/Views/ScheduleView/Model/ScheduleDay.swift @@ -13,19 +13,35 @@ struct ScheduleDay: Hashable, Identifiable, Codable { self.scheduleText = scheduleText self.mockDate = mockDate } + + internal init(date: Date, scheduleText: String, dayTitle: String) { + self.date = date + self.scheduleText = scheduleText + self.dayTitle = dayTitle + } + + internal init(date: Date, scheduleText: String) { + self.date = date + self.scheduleText = scheduleText + } + var mockDate: Date? //Mock representation of current date, for testing - var id = UUID() + var id: Int { + return date.hashValue + } var dayOfTheWeek: Int { Date.getDayOfTheWeek(for: date) } var date: Date //Date of the schedule var scheduleText: String + var dayTitle: String? + var customPeriods = [ClassPeriod]() //Future feature, no use for now var periods: [ClassPeriod] { appendOptionalPeriod8(periods: parseClassPeriods()) } var atheleticsInfo: String { - guard dayOfTheWeek != 6 && dayOfTheWeek != 7 + guard dayOfTheWeek != 6 && dayOfTheWeek != 0 else { return scheduleText } @@ -56,6 +72,7 @@ struct ScheduleDay: Hashable, Identifiable, Codable { return formatter.string(from: date) } + func getCurrentPeriodRemainingTime(selectionMode: PeriodCategory) -> TimeInterval? { if let endTime = getCurrentPeriod(selectionMode: selectionMode)?.endTime, let reference = currentDateReferenceTime { @@ -102,3 +119,4 @@ extension ScheduleDay { static let sampleScheduleDay = ScheduleDay(date: Date(), scheduleText: "Period 6 8:00-9:05\nPeriod 7 9:12-10:22\n(5 minutes for announcements)\nNutrition Period 1\n10:22-11:02 10:29-11:34\nPeriod 1 Nutrition\n11:09-12:14 11:34-12:14\nPeriod 2 12:21-1:26\nOffice Hours 1:33-2:30\n-------------------------------\nAP French Lang/Culture & Modern World Hist 8:00\nAP Macroeconomics 12:00\nB FS Golf vs MD 3:30\nB JV Golf @ JSerra 3:00\nB JV Tennis vs Servite 3:15\nB JV/V LAX @ JSerra 7:00/5:30\nB V Tennis @ Servite 2:30\nB V Vball @ JSerra 3:00\nG JV/V LAX @ Orange Luth 7:00/5:30\nG V Golf vs Rosary 4:30\nPossible G Soccer CIF\nSenior Graduation Ticket Distribution\n\nV Wrestling vs Aliso Niguel 1:30\n") } + diff --git a/Sources/Shared/Views/ScheduleView/Model/ScheduleWeek.swift b/Sources/Shared/Views/ScheduleView/Model/ScheduleWeek.swift index 97bea22..e8f40f1 100644 --- a/Sources/Shared/Views/ScheduleView/Model/ScheduleWeek.swift +++ b/Sources/Shared/Views/ScheduleView/Model/ScheduleWeek.swift @@ -52,6 +52,8 @@ struct ScheduleWeek: Hashable, Codable { extension ScheduleWeek: Equatable { static func == (lhs: ScheduleWeek, rhs: ScheduleWeek) -> Bool { return lhs.startDate == rhs.startDate - && lhs.endDate == rhs.endDate + && lhs.endDate == rhs.endDate + && lhs.weekText == rhs.weekText + && lhs.scheduleDays == rhs.scheduleDays } } diff --git a/Sources/Shared/Views/ScheduleView/ViewModels/ScheduleDateHelper.swift b/Sources/Shared/Views/ScheduleView/ViewModels/ScheduleDateHelper.swift index b84cbce..c931e8c 100644 --- a/Sources/Shared/Views/ScheduleView/ViewModels/ScheduleDateHelper.swift +++ b/Sources/Shared/Views/ScheduleView/ViewModels/ScheduleDateHelper.swift @@ -127,7 +127,9 @@ struct ScheduleDateHelper { } - func parseScheduleXML(forDays days: [(date: String, schedule: String)]) -> [ScheduleWeek] { + func parseScheduleXML(forDays days: [(date: String, + schedule: String, + title: String)]) -> [ScheduleWeek] { // Sort dates into weeks // Same week number of year means same week var scheduleWeek = [ScheduleWeek]() @@ -140,7 +142,9 @@ struct ScheduleDateHelper { #endif continue } - let newDay = ScheduleDay(date: date, scheduleText: day.schedule) + let newDay = ScheduleDay(date: date, + scheduleText: day.schedule, + dayTitle: day.title) scheduleWeek = getScheduleWeekWithNewDay(weeks: scheduleWeek, newDay: newDay) }