From b8c6d440008e2133685c623a3273d527189cfcf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Mu=CC=88ller?= Date: Mon, 1 Feb 2021 23:17:15 +0100 Subject: [PATCH] :sparkles: Adding option to hide RaPla events - Also made changes to home view, lecture plan list view, and added lecture plan item view --- DHBW-Service.xcodeproj/project.pbxproj | 4 + .../DHBW_Service.xcdatamodel/contents | 3 +- DHBW-Service/Utility/RaPlaFetcher.swift | 4 +- DHBW-Service/Utility/UtilityFunctions.swift | 5 +- DHBW-Service/Views/Tabs/HomeView.swift | 119 ++++++++++++++++-- DHBW-Service/Views/Tabs/LecturePlanItem.swift | 57 +++++++++ DHBW-Service/Views/Tabs/LecturePlanList.swift | 54 +++++--- 7 files changed, 214 insertions(+), 32 deletions(-) create mode 100644 DHBW-Service/Views/Tabs/LecturePlanItem.swift diff --git a/DHBW-Service.xcodeproj/project.pbxproj b/DHBW-Service.xcodeproj/project.pbxproj index dda4ae1..47bb99e 100644 --- a/DHBW-Service.xcodeproj/project.pbxproj +++ b/DHBW-Service.xcodeproj/project.pbxproj @@ -31,6 +31,7 @@ CDDCF493259203390027CDC5 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = CDDCF495259203390027CDC5 /* Localizable.strings */; }; CDDCF4A2259203B40027CDC5 /* General.strings in Resources */ = {isa = PBXBuildFile; fileRef = CDDCF4A4259203B40027CDC5 /* General.strings */; }; CDEA70B225C6054F001CFE28 /* LecturePlanList.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDEA70B125C6054F001CFE28 /* LecturePlanList.swift */; }; + CDEA70C025C85999001CFE28 /* LecturePlanItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDEA70BF25C85999001CFE28 /* LecturePlanItem.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -83,6 +84,7 @@ CDDCF4A3259203B40027CDC5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/General.strings; sourceTree = ""; }; CDDCF4A8259203B80027CDC5 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/General.strings; sourceTree = ""; }; CDEA70B125C6054F001CFE28 /* LecturePlanList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LecturePlanList.swift; sourceTree = ""; }; + CDEA70BF25C85999001CFE28 /* LecturePlanItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LecturePlanItem.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -257,6 +259,7 @@ CDCD721925912E1200FBF2F5 /* HomeView.swift */, CDD39B4A259A64150078D05F /* SettingsMain.swift */, CDEA70B125C6054F001CFE28 /* LecturePlanList.swift */, + CDEA70BF25C85999001CFE28 /* LecturePlanItem.swift */, CD730A33259A85F500E0BB69 /* SettingsSubViews */, ); path = Tabs; @@ -441,6 +444,7 @@ CD9FAB83258EC60200D6D0C5 /* ContentView.swift in Sources */, CDCD72242591316500FBF2F5 /* LocalSettings.swift in Sources */, CD8555BE25C47AE500C4ACD6 /* RaPlaFetcher.swift in Sources */, + CDEA70C025C85999001CFE28 /* LecturePlanItem.swift in Sources */, CD8555C325C47B5300C4ACD6 /* ApiService.swift in Sources */, CD9FAB8D258EC60600D6D0C5 /* DHBW_Service.xcdatamodeld in Sources */, CDCD721A25912E1200FBF2F5 /* HomeView.swift in Sources */, diff --git a/DHBW-Service/CoreData/DHBW_Service.xcdatamodeld/DHBW_Service.xcdatamodel/contents b/DHBW-Service/CoreData/DHBW_Service.xcdatamodeld/DHBW_Service.xcdatamodel/contents index 7edf666..ee03929 100644 --- a/DHBW-Service/CoreData/DHBW_Service.xcdatamodeld/DHBW_Service.xcdatamodel/contents +++ b/DHBW-Service/CoreData/DHBW_Service.xcdatamodeld/DHBW_Service.xcdatamodel/contents @@ -7,6 +7,7 @@ + @@ -19,7 +20,7 @@ - + \ No newline at end of file diff --git a/DHBW-Service/Utility/RaPlaFetcher.swift b/DHBW-Service/Utility/RaPlaFetcher.swift index e8ab3c5..287de1c 100644 --- a/DHBW-Service/Utility/RaPlaFetcher.swift +++ b/DHBW-Service/Utility/RaPlaFetcher.swift @@ -134,6 +134,9 @@ class RaPlaFetcher { } else { let entity = NSEntityDescription.entity(forEntityName: "RaPlaEvent", in: PersistenceController.shared.context)! evt = NSManagedObject(entity: entity, insertInto: PersistenceController.shared.context) + + // Set default values for new object + evt.setValue(false, forKey: "isHidden") } evt.setValue(event.startDate, forKey: "startDate") evt.setValue(event.endDate, forKey: "endDate") @@ -150,7 +153,6 @@ class RaPlaFetcher { // Locally stored event does not exist in RaPla anymore, delete it let evt = existingEventsDict[localUid] PersistenceController.shared.context.delete(evt!) - print("Deleted " + localUid) } } diff --git a/DHBW-Service/Utility/UtilityFunctions.swift b/DHBW-Service/Utility/UtilityFunctions.swift index fc63fe6..7389b75 100644 --- a/DHBW-Service/Utility/UtilityFunctions.swift +++ b/DHBW-Service/Utility/UtilityFunctions.swift @@ -9,13 +9,16 @@ import Foundation import CoreData class UtilityFunctions { - public class func getCoreDataObject(entity: String, sortDescriptors: [NSSortDescriptor]) -> [NSManagedObject]{ + public class func getCoreDataObject(entity: String, sortDescriptors: [NSSortDescriptor] = [], searchPredicate: NSPredicate? = nil) -> [NSManagedObject]{ let managedContext = PersistenceController.shared.context let fetchRequest = NSFetchRequest(entityName: entity) fetchRequest.sortDescriptors = sortDescriptors + if(searchPredicate != nil) { + fetchRequest.predicate = searchPredicate + } do { return try managedContext.fetch(fetchRequest) diff --git a/DHBW-Service/Views/Tabs/HomeView.swift b/DHBW-Service/Views/Tabs/HomeView.swift index a9af59c..0be6d59 100644 --- a/DHBW-Service/Views/Tabs/HomeView.swift +++ b/DHBW-Service/Views/Tabs/HomeView.swift @@ -13,30 +13,97 @@ struct HomeView: View { @State private var name: String = "" @State private var course: String = "" @State private var director: String = "" + @State private var todaysEvents: [NSManagedObject] = [] + @State private var tomorrowsEvents: [NSManagedObject] = [] + @State private var upcomingExams: [NSManagedObject] = [] var body: some View { - VStack { - HStack { - Text("name".localized(tableName: "General", plural: false) + ": ") - Text(self.name) - } - HStack { - Text("course".localized(tableName: "General", plural: false) + ": ") - Text(self.course) - } - HStack { - Text("director".localized(tableName: "General", plural: false) + ": ") - Text(self.director) + NavigationView { + VStack { + HStack { + Text("name".localized(tableName: "General", plural: false) + ": ") + Text(self.name) + } + HStack { + Text("course".localized(tableName: "General", plural: false) + ": ") + Text(self.course) + } + HStack { + Text("director".localized(tableName: "General", plural: false) + ": ") + Text(self.director) + } + + // Upcoming events section + HStack { + Spacer() + + VStack { + Text("Today's events") + .font(/*@START_MENU_TOKEN@*/.title/*@END_MENU_TOKEN@*/) + .frame(maxWidth: .infinity) + VStack { + Text("Evt 1") + Text("Evt 2") + } + } + .padding() + .overlay( + RoundedRectangle(cornerRadius: 10) + .stroke(Color.blue, lineWidth: 4) + ) + + VStack { + Text("Tomorrow's events") + .font(/*@START_MENU_TOKEN@*/.title/*@END_MENU_TOKEN@*/) + .frame(maxWidth: .infinity) + VStack { + Text("Evt 1") + Text("Evt 2") + } + } + .padding() + .overlay( + RoundedRectangle(cornerRadius: 10) + .stroke(Color.blue, lineWidth: 4) + ) + + Spacer() + } + + // Exams section + HStack { + Spacer() + + VStack { + Text("Upcoming exams") + .font(/*@START_MENU_TOKEN@*/.title/*@END_MENU_TOKEN@*/) + .frame(maxWidth: .infinity) + VStack { + ForEach(upcomingExams, id: \.self) { exam in + Text(exam.value(forKey: "summary") as! String) + } + } + } + .padding() + .overlay( + RoundedRectangle(cornerRadius: 10) + .stroke(Color.red, lineWidth: 4) + ) + + Spacer() + } } + .navigationBarTitle(Text("Home")) }.onAppear{ self.readFromCoreData() + self.upcomingExams = getUpcomingExams() } } } extension HomeView{ func readFromCoreData() { - let fetchedData = UtilityFunctions.getCoreDataObject(entity: "User", sortDescriptors: []) + let fetchedData = UtilityFunctions.getCoreDataObject(entity: "User") if(!fetchedData.isEmpty) { let user = fetchedData[0] @@ -45,6 +112,32 @@ extension HomeView{ self.director = user.value(forKey: "director") as! String } } + + func getTodaysEvents() -> [NSManagedObject] { +// let searchPredicate = NSPredicate(format: "(category == 'Lehrveranstaltung') AND (startDate = %@)", Date()) +// return Array(UtilityFunctions.getCoreDataObject(entity: "RaPlaEvent", searchPredicate: searchPredicate)[0...1]) + return [] + } + + func getTomorrowsEvents() -> [NSManagedObject] { +// let searchPredicate = NSPredicate(format: "(category == 'Lehrveranstaltung') AND (startDate = %@)", Date().) +// return Array(UtilityFunctions.getCoreDataObject(entity: "RaPlaEvent", searchPredicate: searchPredicate)[0...1]) + return [] + } + + func getUpcomingExams() -> [NSManagedObject] { + let searchPredicate = NSPredicate(format: "category == %@", "Prüfung") + let hiddenPredicate = NSPredicate(format: "isHidden == NO") + let compoundPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [searchPredicate, hiddenPredicate]) + let sectionSortDescriptor = NSSortDescriptor(key: "startDate", ascending: true) + let sortDescriptors = [sectionSortDescriptor] + let events = UtilityFunctions.getCoreDataObject(entity: "RaPlaEvent", sortDescriptors: sortDescriptors, searchPredicate: compoundPredicate) + if(events.count > 0) { + return Array(events[0...min(1, events.count)]) + } else { + return [] + } + } } struct HomeView_Previews: PreviewProvider { diff --git a/DHBW-Service/Views/Tabs/LecturePlanItem.swift b/DHBW-Service/Views/Tabs/LecturePlanItem.swift new file mode 100644 index 0000000..5ebba3b --- /dev/null +++ b/DHBW-Service/Views/Tabs/LecturePlanItem.swift @@ -0,0 +1,57 @@ +// +// LecturePlanItem.swift +// DHBW-Service +// +// Created by Patrick Müller on 01.02.21. +// + +import SwiftUI +import CoreData + +struct LecturePlanItem: View { + @State var event: NSManagedObject + @State var isHidden = false + + var body: some View { + VStack { + Text(event.value(forKey: "summary") as! String) + Button(action: { + event.setValue(!isHidden, forKey: "isHidden") + self.isHidden = !isHidden + PersistenceController.shared.save() + }){ + if(self.isHidden){ + Text("Show") + } else { + Text("Hide") + } + } + .padding() + .foregroundColor(.white) + .background(Color.blue) + .cornerRadius(15) + } + .onAppear{ + self.isHidden = event.value(forKey: "isHidden") as! Bool + } + } +} + +struct LecturePlanItem_Previews: PreviewProvider { + static var previews: some View { + LecturePlanItem(event: getPreviewEvent()) + .preferredColorScheme(.dark) + .environmentObject(getFirstOpening()) + .environment(\.managedObjectContext, PersistenceController.preview.container.viewContext) + } + + static func getFirstOpening() -> LocalSettings { + let settings = LocalSettings(); + settings.isFirstOpening = false; + return settings + } + + static func getPreviewEvent() -> NSManagedObject { + return UtilityFunctions.getCoreDataObject(entity: "RaPlaEvent", sortDescriptors: [])[0] + } +} diff --git a/DHBW-Service/Views/Tabs/LecturePlanList.swift b/DHBW-Service/Views/Tabs/LecturePlanList.swift index 04e74e9..5587cb2 100644 --- a/DHBW-Service/Views/Tabs/LecturePlanList.swift +++ b/DHBW-Service/Views/Tabs/LecturePlanList.swift @@ -13,30 +13,52 @@ struct LecturePlanList: View { @State private var sortingAscending = true var body: some View { - VStack { - Button(action: { - // This is obviously bullshit, but it could be used to sort afer summary or smth like that - - self.sortingAscending = !self.sortingAscending - let sectionSortDescriptor = NSSortDescriptor(key: "startDate", ascending: sortingAscending) - let sortDescriptors = [sectionSortDescriptor] - self.events = UtilityFunctions.getCoreDataObject(entity: "RaPlaEvent", sortDescriptors: sortDescriptors) - }){ - Text("Switch order") - } + NavigationView() { List { ForEach(events, id: \.self) { event in - HStack { - Text(formatDate(date: event.value(forKeyPath: "startDate") as! Date)) - .foregroundColor(getEventForegroundColor(for: event)) - Text(event.value(forKeyPath: "summary") as! String) - .foregroundColor(getEventForegroundColor(for: event)) + NavigationLink(destination: LecturePlanItem(event: event)){ + HStack { + Text(formatDate(date: event.value(forKeyPath: "startDate") as! Date)) + .foregroundColor(getEventForegroundColor(for: event)) + Text(event.value(forKeyPath: "summary") as! String) + .foregroundColor(getEventForegroundColor(for: event)) + + Spacer() + + if(event.value(forKey: "isHidden") as! Bool) { + Image(systemName: "eye.slash") + .foregroundColor(.red) + } else { + Image(systemName: "eye") + } + } } + // When an event gets updated from child view, reload it here as this will not trigger the onAppear() function + .onReceive(event.objectWillChange, perform: { _ in + let sectionSortDescriptor = NSSortDescriptor(key: "startDate", ascending: true) + let sortDescriptors = [sectionSortDescriptor] + self.events = [] + self.events = UtilityFunctions.getCoreDataObject(entity: "RaPlaEvent", sortDescriptors: sortDescriptors) + }) } } + .navigationBarTitle(Text("Lectures")) + // .navigationBarItems(trailing: { + // Button(action: { + // // This is obviously bullshit, but it could be used to sort afer summary or smth like that + // + // self.sortingAscending = !self.sortingAscending + // let sectionSortDescriptor = NSSortDescriptor(key: "startDate", ascending: sortingAscending) + // let sortDescriptors = [sectionSortDescriptor] + // self.events = UtilityFunctions.getCoreDataObject(entity: "RaPlaEvent", sortDescriptors: sortDescriptors) + // }){ + // Text("Switch order") + // } + // }) }.onAppear{ let sectionSortDescriptor = NSSortDescriptor(key: "startDate", ascending: true) let sortDescriptors = [sectionSortDescriptor] + self.events = [] self.events = UtilityFunctions.getCoreDataObject(entity: "RaPlaEvent", sortDescriptors: sortDescriptors) } }