mirror of
https://github.com/Mueller-Patrick/DHBW-Service-App.git
synced 2024-11-25 02:23:56 +00:00
✨ Added base for lecture plan view
This commit is contained in:
parent
81f9e8706c
commit
95f06cc87d
|
@ -12,6 +12,8 @@
|
||||||
CD2FC0C725A869FE00963178 /* alpaca-alt-icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = CD2FC0C325A869FE00963178 /* alpaca-alt-icon@2x.png */; };
|
CD2FC0C725A869FE00963178 /* alpaca-alt-icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = CD2FC0C325A869FE00963178 /* alpaca-alt-icon@2x.png */; };
|
||||||
CD2FC0C825A869FE00963178 /* alpaca-alt-icon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = CD2FC0C425A869FE00963178 /* alpaca-alt-icon@3x.png */; };
|
CD2FC0C825A869FE00963178 /* alpaca-alt-icon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = CD2FC0C425A869FE00963178 /* alpaca-alt-icon@3x.png */; };
|
||||||
CD730A35259A860E00E0BB69 /* SettingsAcknowledgements.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD730A34259A860E00E0BB69 /* SettingsAcknowledgements.swift */; };
|
CD730A35259A860E00E0BB69 /* SettingsAcknowledgements.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD730A34259A860E00E0BB69 /* SettingsAcknowledgements.swift */; };
|
||||||
|
CD8555BE25C47AE500C4ACD6 /* RaPlaFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD8555BD25C47AE500C4ACD6 /* RaPlaFetcher.swift */; };
|
||||||
|
CD8555C325C47B5300C4ACD6 /* ApiService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD8555C225C47B5300C4ACD6 /* ApiService.swift */; };
|
||||||
CD9FAB81258EC60200D6D0C5 /* DHBW_ServiceApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD9FAB80258EC60200D6D0C5 /* DHBW_ServiceApp.swift */; };
|
CD9FAB81258EC60200D6D0C5 /* DHBW_ServiceApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD9FAB80258EC60200D6D0C5 /* DHBW_ServiceApp.swift */; };
|
||||||
CD9FAB83258EC60200D6D0C5 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD9FAB82258EC60200D6D0C5 /* ContentView.swift */; };
|
CD9FAB83258EC60200D6D0C5 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD9FAB82258EC60200D6D0C5 /* ContentView.swift */; };
|
||||||
CD9FAB85258EC60600D6D0C5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CD9FAB84258EC60600D6D0C5 /* Assets.xcassets */; };
|
CD9FAB85258EC60600D6D0C5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CD9FAB84258EC60600D6D0C5 /* Assets.xcassets */; };
|
||||||
|
@ -28,6 +30,7 @@
|
||||||
CDDCF4842592028A0027CDC5 /* Localizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDDCF4832592028A0027CDC5 /* Localizer.swift */; };
|
CDDCF4842592028A0027CDC5 /* Localizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDDCF4832592028A0027CDC5 /* Localizer.swift */; };
|
||||||
CDDCF493259203390027CDC5 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = CDDCF495259203390027CDC5 /* Localizable.strings */; };
|
CDDCF493259203390027CDC5 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = CDDCF495259203390027CDC5 /* Localizable.strings */; };
|
||||||
CDDCF4A2259203B40027CDC5 /* General.strings in Resources */ = {isa = PBXBuildFile; fileRef = CDDCF4A4259203B40027CDC5 /* General.strings */; };
|
CDDCF4A2259203B40027CDC5 /* General.strings in Resources */ = {isa = PBXBuildFile; fileRef = CDDCF4A4259203B40027CDC5 /* General.strings */; };
|
||||||
|
CDEA70B225C6054F001CFE28 /* LecturePlanList.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDEA70B125C6054F001CFE28 /* LecturePlanList.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
@ -53,6 +56,8 @@
|
||||||
CD2FC0C325A869FE00963178 /* alpaca-alt-icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "alpaca-alt-icon@2x.png"; sourceTree = "<group>"; };
|
CD2FC0C325A869FE00963178 /* alpaca-alt-icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "alpaca-alt-icon@2x.png"; sourceTree = "<group>"; };
|
||||||
CD2FC0C425A869FE00963178 /* alpaca-alt-icon@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "alpaca-alt-icon@3x.png"; sourceTree = "<group>"; };
|
CD2FC0C425A869FE00963178 /* alpaca-alt-icon@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "alpaca-alt-icon@3x.png"; sourceTree = "<group>"; };
|
||||||
CD730A34259A860E00E0BB69 /* SettingsAcknowledgements.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAcknowledgements.swift; sourceTree = "<group>"; };
|
CD730A34259A860E00E0BB69 /* SettingsAcknowledgements.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAcknowledgements.swift; sourceTree = "<group>"; };
|
||||||
|
CD8555BD25C47AE500C4ACD6 /* RaPlaFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RaPlaFetcher.swift; sourceTree = "<group>"; };
|
||||||
|
CD8555C225C47B5300C4ACD6 /* ApiService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiService.swift; sourceTree = "<group>"; };
|
||||||
CD9FAB7D258EC60200D6D0C5 /* DHBW-Service.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DHBW-Service.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
CD9FAB7D258EC60200D6D0C5 /* DHBW-Service.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DHBW-Service.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
CD9FAB80258EC60200D6D0C5 /* DHBW_ServiceApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DHBW_ServiceApp.swift; sourceTree = "<group>"; };
|
CD9FAB80258EC60200D6D0C5 /* DHBW_ServiceApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DHBW_ServiceApp.swift; sourceTree = "<group>"; };
|
||||||
CD9FAB82258EC60200D6D0C5 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
CD9FAB82258EC60200D6D0C5 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||||
|
@ -77,6 +82,7 @@
|
||||||
CDDCF4992592033F0027CDC5 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
|
CDDCF4992592033F0027CDC5 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
CDDCF4A3259203B40027CDC5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/General.strings; sourceTree = "<group>"; };
|
CDDCF4A3259203B40027CDC5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/General.strings; sourceTree = "<group>"; };
|
||||||
CDDCF4A8259203B80027CDC5 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/General.strings; sourceTree = "<group>"; };
|
CDDCF4A8259203B80027CDC5 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/General.strings; sourceTree = "<group>"; };
|
||||||
|
CDEA70B125C6054F001CFE28 /* LecturePlanList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LecturePlanList.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
@ -250,6 +256,7 @@
|
||||||
children = (
|
children = (
|
||||||
CDCD721925912E1200FBF2F5 /* HomeView.swift */,
|
CDCD721925912E1200FBF2F5 /* HomeView.swift */,
|
||||||
CDD39B4A259A64150078D05F /* SettingsMain.swift */,
|
CDD39B4A259A64150078D05F /* SettingsMain.swift */,
|
||||||
|
CDEA70B125C6054F001CFE28 /* LecturePlanList.swift */,
|
||||||
CD730A33259A85F500E0BB69 /* SettingsSubViews */,
|
CD730A33259A85F500E0BB69 /* SettingsSubViews */,
|
||||||
);
|
);
|
||||||
path = Tabs;
|
path = Tabs;
|
||||||
|
@ -275,6 +282,8 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
CDDCF47A2591FE550027CDC5 /* UtilityFunctions.swift */,
|
CDDCF47A2591FE550027CDC5 /* UtilityFunctions.swift */,
|
||||||
|
CD8555BD25C47AE500C4ACD6 /* RaPlaFetcher.swift */,
|
||||||
|
CD8555C225C47B5300C4ACD6 /* ApiService.swift */,
|
||||||
);
|
);
|
||||||
path = Utility;
|
path = Utility;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -431,9 +440,12 @@
|
||||||
CD730A35259A860E00E0BB69 /* SettingsAcknowledgements.swift in Sources */,
|
CD730A35259A860E00E0BB69 /* SettingsAcknowledgements.swift in Sources */,
|
||||||
CD9FAB83258EC60200D6D0C5 /* ContentView.swift in Sources */,
|
CD9FAB83258EC60200D6D0C5 /* ContentView.swift in Sources */,
|
||||||
CDCD72242591316500FBF2F5 /* LocalSettings.swift in Sources */,
|
CDCD72242591316500FBF2F5 /* LocalSettings.swift in Sources */,
|
||||||
|
CD8555BE25C47AE500C4ACD6 /* RaPlaFetcher.swift in Sources */,
|
||||||
|
CD8555C325C47B5300C4ACD6 /* ApiService.swift in Sources */,
|
||||||
CD9FAB8D258EC60600D6D0C5 /* DHBW_Service.xcdatamodeld in Sources */,
|
CD9FAB8D258EC60600D6D0C5 /* DHBW_Service.xcdatamodeld in Sources */,
|
||||||
CDCD721A25912E1200FBF2F5 /* HomeView.swift in Sources */,
|
CDCD721A25912E1200FBF2F5 /* HomeView.swift in Sources */,
|
||||||
CDD39B4B259A64150078D05F /* SettingsMain.swift in Sources */,
|
CDD39B4B259A64150078D05F /* SettingsMain.swift in Sources */,
|
||||||
|
CDEA70B225C6054F001CFE28 /* LecturePlanList.swift in Sources */,
|
||||||
CDDCF47B2591FE550027CDC5 /* UtilityFunctions.swift in Sources */,
|
CDDCF47B2591FE550027CDC5 /* UtilityFunctions.swift in Sources */,
|
||||||
CD9FAB81258EC60200D6D0C5 /* DHBW_ServiceApp.swift in Sources */,
|
CD9FAB81258EC60200D6D0C5 /* DHBW_ServiceApp.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="17511" systemVersion="20C69" minimumToolsVersion="Automatic" sourceLanguage="Swift" usedWithCloudKit="YES" userDefinedModelVersionIdentifier="">
|
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="17709" systemVersion="20D62" minimumToolsVersion="Automatic" sourceLanguage="Swift" usedWithCloudKit="YES" userDefinedModelVersionIdentifier="">
|
||||||
<entity name="Item" representedClassName="Item" syncable="YES" codeGenerationType="class">
|
<entity name="Item" representedClassName="Item" syncable="YES" codeGenerationType="class">
|
||||||
<attribute name="timestamp" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
<attribute name="timestamp" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||||
</entity>
|
</entity>
|
||||||
|
<entity name="RaPlaEvent" representedClassName="RaPlaEvent" syncable="YES" codeGenerationType="class">
|
||||||
|
<attribute name="category" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="descr" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="endDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||||
|
<attribute name="location" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="startDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||||
|
<attribute name="summary" optional="YES" attributeType="String"/>
|
||||||
|
</entity>
|
||||||
<entity name="User" representedClassName="User" syncable="YES" codeGenerationType="class">
|
<entity name="User" representedClassName="User" syncable="YES" codeGenerationType="class">
|
||||||
<attribute name="course" optional="YES" attributeType="String"/>
|
<attribute name="course" optional="YES" attributeType="String"/>
|
||||||
<attribute name="director" optional="YES" attributeType="String"/>
|
<attribute name="director" optional="YES" attributeType="String"/>
|
||||||
|
@ -11,5 +19,6 @@
|
||||||
<elements>
|
<elements>
|
||||||
<element name="Item" positionX="-63" positionY="-18" width="128" height="44"/>
|
<element name="Item" positionX="-63" positionY="-18" width="128" height="44"/>
|
||||||
<element name="User" positionX="-63" positionY="-9" width="128" height="74"/>
|
<element name="User" positionX="-63" positionY="-9" width="128" height="74"/>
|
||||||
|
<element name="RaPlaEvent" positionX="-63" positionY="9" width="128" height="119"/>
|
||||||
</elements>
|
</elements>
|
||||||
</model>
|
</model>
|
89
DHBW-Service/Utility/ApiService.swift
Normal file
89
DHBW-Service/Utility/ApiService.swift
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
//
|
||||||
|
// ApiService.swift
|
||||||
|
// DHBW-Service
|
||||||
|
//
|
||||||
|
// Created by Patrick Müller on 29.01.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class ApiService {
|
||||||
|
// MARK: HTTP POST Request
|
||||||
|
public class func callPost(url: URL, parameters: [String:Any], finish: @escaping ((message: String, data: Data?)) -> Void) {
|
||||||
|
var request = URLRequest(url: url)
|
||||||
|
request.httpMethod = "POST"
|
||||||
|
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
|
||||||
|
request.addValue("application/json", forHTTPHeaderField: "Accept")
|
||||||
|
|
||||||
|
// Set params
|
||||||
|
let postString = self.getPostString(params: parameters)
|
||||||
|
request.httpBody = postString.data(using: .utf8)
|
||||||
|
|
||||||
|
var result: (message: String, data:Data?) = (message: "Fail", data: nil)
|
||||||
|
let task = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in
|
||||||
|
do {
|
||||||
|
guard error == nil else {
|
||||||
|
throw HttpFetchError.fetchError
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let data = data else {
|
||||||
|
throw HttpFetchError.noDataReceivedError
|
||||||
|
}
|
||||||
|
|
||||||
|
result.message = "Success"
|
||||||
|
result.data = data
|
||||||
|
} catch let error {
|
||||||
|
print(error.localizedDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
finish(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
task.resume()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: HTTP GET Request
|
||||||
|
public class func callGet(url: URL, finish: @escaping ((message: String, data: Data?)) -> Void) {
|
||||||
|
var request = URLRequest(url: url)
|
||||||
|
request.httpMethod = "GET"
|
||||||
|
//request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
|
||||||
|
//request.addValue("application/json", forHTTPHeaderField: "Accept")
|
||||||
|
|
||||||
|
var result: (message: String, data:Data?) = (message: "Fail", data: nil)
|
||||||
|
let task = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in
|
||||||
|
do {
|
||||||
|
guard error == nil else {
|
||||||
|
throw HttpFetchError.fetchError
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let data = data else {
|
||||||
|
throw HttpFetchError.noDataReceivedError
|
||||||
|
}
|
||||||
|
|
||||||
|
result.message = "Success"
|
||||||
|
result.data = data
|
||||||
|
} catch let error {
|
||||||
|
print(error.localizedDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
finish(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
task.resume()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Data preparation
|
||||||
|
private class func getPostString(params: [String:Any]) -> String {
|
||||||
|
var data = [String]()
|
||||||
|
for(key, value) in params{
|
||||||
|
data.append(key + "=\(value)")
|
||||||
|
}
|
||||||
|
return data.map{String($0)}.joined(separator: "&")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Error enum
|
||||||
|
private enum HttpFetchError: Error {
|
||||||
|
case fetchError
|
||||||
|
case noDataReceivedError
|
||||||
|
}
|
||||||
|
}
|
138
DHBW-Service/Utility/RaPlaFetcher.swift
Normal file
138
DHBW-Service/Utility/RaPlaFetcher.swift
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
//
|
||||||
|
// RaPlaFetcher.swift
|
||||||
|
// DHBW-Service
|
||||||
|
//
|
||||||
|
// Created by Patrick Müller on 29.01.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import CoreData
|
||||||
|
|
||||||
|
class RaPlaFetcher {
|
||||||
|
public class iCalEvent {
|
||||||
|
var startDate: Date = Date() //DTSTART
|
||||||
|
var endDate: Date = Date() //DTEND
|
||||||
|
var summary: String = "" //SUMMARY
|
||||||
|
var description: String = "" //DESCRIPTION
|
||||||
|
var location: String = "" //LOCATION
|
||||||
|
var category: String = "" //CATEGORIES
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the RaPla file from the given URL and save the events to CoreData
|
||||||
|
public class func getRaplaFileAndSaveToCoreData(from urlString: String) -> Bool {
|
||||||
|
let file = getFileAsString(from: urlString)
|
||||||
|
|
||||||
|
let eventStrings = splitIntoEvents(file: file)
|
||||||
|
|
||||||
|
let eventObjects = convertStringsToObjects(eventStrings: eventStrings)
|
||||||
|
|
||||||
|
return saveToCoreData(eventObjects: eventObjects)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the RaPla files from the given URL and return the event objects
|
||||||
|
public class func getRaplaFileAndReturnEvents(from urlString: String) -> [iCalEvent] {
|
||||||
|
let file = getFileAsString(from: urlString)
|
||||||
|
|
||||||
|
let eventStrings = splitIntoEvents(file: file)
|
||||||
|
|
||||||
|
return convertStringsToObjects(eventStrings: eventStrings)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET the file from the given URL and convert it to a String that is then returned
|
||||||
|
private class func getFileAsString(from urlString: String) -> String {
|
||||||
|
let url = URL(string: urlString)!
|
||||||
|
var file: String = ""
|
||||||
|
|
||||||
|
do {
|
||||||
|
file = try String(contentsOf: url, encoding: .utf8)
|
||||||
|
} catch let error {
|
||||||
|
print(error.localizedDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split the given ical file string into individual event strings and return them as a list
|
||||||
|
private class func splitIntoEvents(file: String) -> [String] {
|
||||||
|
let regexOptions: NSRegularExpression.Options = [.dotMatchesLineSeparators]
|
||||||
|
// Regex explanation: Matches BEGIN:VEVENT "Any character" END:VEVENT across multiple lines. The *? assures that we receive the
|
||||||
|
// maximum amount of matches, i.e. it makes the regex non-greedy as we would otherwise just receive one giant match
|
||||||
|
let eventStrings = UtilityFunctions.regexMatches(for: "BEGIN:VEVENT.*?END:VEVENT", with: regexOptions, in: file)
|
||||||
|
|
||||||
|
return eventStrings
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert an ical event String into an iCalEvent Codable object as defined above
|
||||||
|
private class func convertStringsToObjects(eventStrings: [String]) -> [iCalEvent] {
|
||||||
|
var events: [iCalEvent] = []
|
||||||
|
|
||||||
|
for eventString in eventStrings {
|
||||||
|
let lines = eventString.components(separatedBy: .newlines)
|
||||||
|
let evt = iCalEvent()
|
||||||
|
|
||||||
|
for line in lines {
|
||||||
|
var lineWithoutPrefix = line
|
||||||
|
if(!line.contains(":")) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lineWithoutPrefix.removeSubrange(lineWithoutPrefix.startIndex...lineWithoutPrefix.firstIndex(of: ":")!)
|
||||||
|
|
||||||
|
if(line.hasPrefix("DTSTART")){
|
||||||
|
//Date format: 20181101T080000
|
||||||
|
let dateFormatter = DateFormatter()
|
||||||
|
if(lineWithoutPrefix.contains("Z")){
|
||||||
|
dateFormatter.dateFormat = "yyyyMMdd'T'HHmmssZ"
|
||||||
|
} else {
|
||||||
|
dateFormatter.dateFormat = "yyyyMMdd'T'HHmmss"
|
||||||
|
}
|
||||||
|
let date = dateFormatter.date(from: lineWithoutPrefix)!
|
||||||
|
evt.startDate = date
|
||||||
|
} else if(line.hasPrefix("DTEND")){
|
||||||
|
let dateFormatter = DateFormatter()
|
||||||
|
if(lineWithoutPrefix.contains("Z")){
|
||||||
|
dateFormatter.dateFormat = "yyyyMMdd'T'HHmmssZ"
|
||||||
|
} else {
|
||||||
|
dateFormatter.dateFormat = "yyyyMMdd'T'HHmmss"
|
||||||
|
}
|
||||||
|
let date = dateFormatter.date(from: lineWithoutPrefix)!
|
||||||
|
evt.endDate = date
|
||||||
|
} else if(line.hasPrefix("SUMMARY")){
|
||||||
|
evt.summary = lineWithoutPrefix
|
||||||
|
} else if(line.hasPrefix("DESCRIPTION")){
|
||||||
|
evt.description = lineWithoutPrefix
|
||||||
|
} else if(line.hasPrefix("LOCATION")){
|
||||||
|
evt.location = lineWithoutPrefix
|
||||||
|
} else if(line.hasPrefix("CATEGORIES")){
|
||||||
|
evt.category = lineWithoutPrefix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
events.append(evt)
|
||||||
|
}
|
||||||
|
|
||||||
|
return events
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the given iCalEvent objects to CoreData
|
||||||
|
private class func saveToCoreData(eventObjects: [iCalEvent]) -> Bool{
|
||||||
|
// Delete old data
|
||||||
|
if(UtilityFunctions.deleteAllCoreDataEntitiesOfType(type: "RaPlaEvent")){
|
||||||
|
for event in eventObjects {
|
||||||
|
let entity = NSEntityDescription.entity(forEntityName: "RaPlaEvent", in: PersistenceController.shared.context)!
|
||||||
|
let evt = NSManagedObject(entity: entity, insertInto: PersistenceController.shared.context)
|
||||||
|
evt.setValue(event.startDate, forKey: "startDate")
|
||||||
|
evt.setValue(event.endDate, forKey: "endDate")
|
||||||
|
evt.setValue(event.summary, forKey: "summary")
|
||||||
|
evt.setValue(event.description, forKey: "descr")
|
||||||
|
evt.setValue(event.location, forKey: "location")
|
||||||
|
evt.setValue(event.category, forKey: "category")
|
||||||
|
}
|
||||||
|
|
||||||
|
PersistenceController.shared.save()
|
||||||
|
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,12 +9,13 @@ import Foundation
|
||||||
import CoreData
|
import CoreData
|
||||||
|
|
||||||
class UtilityFunctions {
|
class UtilityFunctions {
|
||||||
public class func getCoreDataObject(entity: String) -> [NSManagedObject]{
|
public class func getCoreDataObject(entity: String, sortDescriptors: [NSSortDescriptor]) -> [NSManagedObject]{
|
||||||
let managedContext =
|
let managedContext =
|
||||||
PersistenceController.shared.context
|
PersistenceController.shared.context
|
||||||
|
|
||||||
let fetchRequest =
|
let fetchRequest =
|
||||||
NSFetchRequest<NSManagedObject>(entityName: entity)
|
NSFetchRequest<NSManagedObject>(entityName: entity)
|
||||||
|
fetchRequest.sortDescriptors = sortDescriptors
|
||||||
|
|
||||||
do {
|
do {
|
||||||
return try managedContext.fetch(fetchRequest)
|
return try managedContext.fetch(fetchRequest)
|
||||||
|
@ -60,4 +61,20 @@ class UtilityFunctions {
|
||||||
|
|
||||||
return allSuccessful
|
return allSuccessful
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: Find matches in the given text for the given regex string.
|
||||||
|
public class func regexMatches(for regex: String, with options: NSRegularExpression.Options, in text: String) -> [String] {
|
||||||
|
|
||||||
|
do {
|
||||||
|
let regex = try NSRegularExpression(pattern: regex, options: options)
|
||||||
|
let results = regex.matches(in: text,
|
||||||
|
range: NSRange(text.startIndex..., in: text))
|
||||||
|
return results.map {
|
||||||
|
String(text[Range($0.range, in: text)!])
|
||||||
|
}
|
||||||
|
} catch let error {
|
||||||
|
print("invalid regex: \(error.localizedDescription)")
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,14 @@ struct ContentView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.tag(0)
|
.tag(0)
|
||||||
|
LecturePlanList()
|
||||||
|
.tabItem {
|
||||||
|
VStack {
|
||||||
|
Image(systemName: "calendar")
|
||||||
|
Text("Lecture Plan")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tag(1)
|
||||||
SettingsMain()
|
SettingsMain()
|
||||||
.tabItem {
|
.tabItem {
|
||||||
VStack {
|
VStack {
|
||||||
|
@ -33,10 +41,14 @@ struct ContentView: View {
|
||||||
Text("Settings")
|
Text("Settings")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.tag(1)
|
.tag(2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.onAppear{
|
||||||
|
// Called upon the opening of the app
|
||||||
|
RaPlaFetcher.getRaplaFileAndSaveToCoreData(from: "https://rapla.dhbw-karlsruhe.de/rapla?page=ical&user=eisenbiegler&file=TINF19B4")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ struct HomeView: View {
|
||||||
|
|
||||||
extension HomeView{
|
extension HomeView{
|
||||||
func readFromCoreData() {
|
func readFromCoreData() {
|
||||||
let fetchedData = UtilityFunctions.getCoreDataObject(entity: "User")
|
let fetchedData = UtilityFunctions.getCoreDataObject(entity: "User", sortDescriptors: [])
|
||||||
|
|
||||||
if(!fetchedData.isEmpty) {
|
if(!fetchedData.isEmpty) {
|
||||||
let user = fetchedData[0]
|
let user = fetchedData[0]
|
||||||
|
|
42
DHBW-Service/Views/Tabs/LecturePlanList.swift
Normal file
42
DHBW-Service/Views/Tabs/LecturePlanList.swift
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
//
|
||||||
|
// LecturePlanList.swift
|
||||||
|
// DHBW-Service
|
||||||
|
//
|
||||||
|
// Created by Patrick Müller on 30.01.21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import CoreData
|
||||||
|
|
||||||
|
struct LecturePlanList: View {
|
||||||
|
@State private var events: [NSManagedObject] = []
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
List {
|
||||||
|
ForEach(events, id: \.self) { event in
|
||||||
|
HStack {
|
||||||
|
Text(formatDate(date: event.value(forKeyPath: "startDate") as! Date))
|
||||||
|
Text(event.value(forKeyPath: "summary") as! String)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.onAppear{
|
||||||
|
let sectionSortDescriptor = NSSortDescriptor(key: "startDate", ascending: true)
|
||||||
|
let sortDescriptors = [sectionSortDescriptor]
|
||||||
|
self.events = UtilityFunctions.getCoreDataObject(entity: "RaPlaEvent", sortDescriptors: sortDescriptors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LecturePlanList_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
LecturePlanList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension LecturePlanList {
|
||||||
|
private func formatDate(date: Date) -> String {
|
||||||
|
let formatter = DateFormatter()
|
||||||
|
formatter.dateStyle = .short
|
||||||
|
return formatter.string(from: date)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user