diff --git a/AvH Plan.xcodeproj/project.pbxproj b/AvH Plan.xcodeproj/project.pbxproj index 162238a..6d80b39 100644 --- a/AvH Plan.xcodeproj/project.pbxproj +++ b/AvH Plan.xcodeproj/project.pbxproj @@ -198,30 +198,30 @@ children = ( A99AB5F7230155DE00555295 /* GoogleService-Info.plist */, A961337F2299867400B541D4 /* AppDelegate.swift */, + A9B0464B22E1F255005FB0DB /* CustomTabBarController.swift */, + A9378D342336015000C07D07 /* LoginViewController.swift */, + A9378D382336300700C07D07 /* FirstTimeViewController.swift */, A96133812299867400B541D4 /* PlanViewController.swift */, + A96D4CC722DDE01A006BAB34 /* GeneralPlanViewController.swift */, + A96D4CC922DDE184006BAB34 /* PersonalPlanViewController.swift */, A9C1D2FF22D656DD00139043 /* MenuViewController.swift */, + A9B0464D22E1F75A005FB0DB /* CustomizationViewController.swift */, + A9B0464F22E21207005FB0DB /* ColourPickerView.swift */, + A9C1D30122D7237200139043 /* DataFetcher.swift */, A96133852299867400B541D4 /* Main.storyboard */, A96133882299867A00B541D4 /* Assets.xcassets */, + A958A92422DF5388007052B0 /* Localizable.strings */, A961338A2299867A00B541D4 /* LaunchScreen.storyboard */, A996BFED22E0586500E7BE42 /* Info.plist */, + A996BFFB22E05AAB00E7BE42 /* InfoPlist.strings */, A9A3496B22D4859200F35AE0 /* SubstModel.swift */, - A9C1D30122D7237200139043 /* DataFetcher.swift */, A957A74F22DDC15500E0A2ED /* MenuViewCell.swift */, A957A75022DDC15500E0A2ED /* MenuViewCell.xib */, A9D830A522DE258C00D7EA05 /* PlanViewCell.swift */, A9D830A622DE258C00D7EA05 /* PlanViewCell.xib */, - A96D4CC722DDE01A006BAB34 /* GeneralPlanViewController.swift */, - A96D4CC922DDE184006BAB34 /* PersonalPlanViewController.swift */, - A958A92422DF5388007052B0 /* Localizable.strings */, - A996BFFB22E05AAB00E7BE42 /* InfoPlist.strings */, - A9B0464B22E1F255005FB0DB /* CustomTabBarController.swift */, - A9B0464D22E1F75A005FB0DB /* CustomizationViewController.swift */, - A9B0464F22E21207005FB0DB /* ColourPickerView.swift */, A9B0465322E448EC005FB0DB /* GenericViewCell.swift */, A9B033D622E4D0AB009ACF8A /* ColourViewCell.swift */, A9B033D722E4D0AB009ACF8A /* ColourViewCell.xib */, - A9378D342336015000C07D07 /* LoginViewController.swift */, - A9378D382336300700C07D07 /* FirstTimeViewController.swift */, ); path = "AvH Plan"; sourceTree = ""; diff --git a/AvH Plan/DataFetcher.swift b/AvH Plan/DataFetcher.swift index 9421ddf..178ca9e 100644 --- a/AvH Plan/DataFetcher.swift +++ b/AvH Plan/DataFetcher.swift @@ -18,11 +18,13 @@ class DataFetcher { let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! let prefs = UserDefaults.standard + let juniors = ["5", "6", "7", "8", "9"] let substitutions = Table("substitutions") let personal = Table("personal") let information = Table("information") let foodmenu = Table("foodmenu") + let id = Expression("id") let group = Expression("group") let course = Expression("course") @@ -31,10 +33,14 @@ class DataFetcher { let time = Expression("time") let room = Expression("room") let teacher = Expression("teacher") - let substType = Expression("type") + let subst_type = Expression("type") + let group_priority = Expression("group_priority") + let date_priority = Expression("date_priority") + let website_priority = Expression("website_priority") + let text = Expression("text") - func doAsync(do task: String, completionHandler: @escaping (_ substitutions: [Any]) -> ()) { + func doAsync(do task: String, completionHandler: @escaping (_ substitutions: Any) -> ()) { DispatchQueue(label: "work-queue").async { let foodUrl = "https://djd4rkn355.github.io/food.html" let url = "https://djd4rkn355.github.io/avh_substitutions.html" @@ -50,24 +56,8 @@ class DataFetcher { } } - func parseHTML(html: String, food: String, type: String) -> [Any] { - var subst = [SubstModel]() - var personalSubst = [SubstModel]() - var info = "" - var infoList = [String]() - var menuList = [String]() - var isPersonalEmpty = true - var personalPlanCount = 0 + private func createAndClearTables(in db: Connection) -> Bool { do { - let doc = try SwiftSoup.parse(html) - - let rows: Elements = try doc.select("tr") - - let courses = prefs.string(forKey: "courses") - let classes = prefs.string(forKey: "classes") - - let db = try Connection("\(path)/db.sqlite3") - try db.run(substitutions.create(ifNotExists: true) { t in t.column(id, primaryKey: true) t.column(group) @@ -77,7 +67,10 @@ class DataFetcher { t.column(time) t.column(room) t.column(teacher) - t.column(substType) + t.column(subst_type) + t.column(group_priority) + t.column(date_priority) + t.column(website_priority) }) try db.run(personal.create(ifNotExists: true) { t in @@ -89,15 +82,108 @@ class DataFetcher { t.column(time) t.column(room) t.column(teacher) - t.column(substType) + t.column(subst_type) + t.column(group_priority) + t.column(date_priority) + t.column(website_priority) + }) + + try db.run(foodmenu.create(ifNotExists: true) { t in + t.column(id, primaryKey: true) + t.column(text) }) try db.run(substitutions.delete()) try db.run(personal.delete()) + try db.run(foodmenu.delete()) + + return true + } catch { + return false + } + } + + private func insert(into table: Table, substitution s: SubstModel) -> Insert { + + return table.insert(group <- s.group, course <- s.course, additional <- s.additional, date <- s.date, time <- s.time, room <- s.room, teacher <- s.teacher, subst_type <- s.type, group_priority <- Int64(s.groupPriority), date_priority <- Int64(s.datePriority), website_priority <- Int64(s.websitePriority)) + } + + private func isPersonal(with g: String, and c: String, for s: SubstModel) -> Bool { + if !g.isEmpty && c.isEmpty { + if !s.group.isEmpty { + if g.contains(s.group) || s.group.contains(g) { + return true + } + } + } else if !g.isEmpty && !c.isEmpty { + if s.group != "" && s.course != "" { + if (g.contains(s.group) || s.group.contains(g)) && c.contains(s.course) { + return true + } + } + } + return false + } + + private func assignRanking(for group: String, _ isPSA: Bool) -> Int { + if isPSA { + return -31 + } + + if group.count > 0 { + let a = String(group[...group.startIndex]) + if self.checkStringForArray(s: a, checking: juniors) == true { + return -30 + } else if a == "1" || a == "2" { + if group.count > 1 { + let b = Int(String(group[group.index(group.startIndex, offsetBy: 1)...group.index(group.startIndex, offsetBy: 1)])) + if b == nil { + return 0 + } else { + return (b! - (b! * 2)) + } + } else { + return 0 + } + } else { + return -29 + } + } + + return 0 + } + + private func assignDatePriority(for d: String, _ isPSA: Bool) -> Int? { + + if isPSA { + return -1 + } + + let periodIndex = d.firstIndex(of: ".") + + return Int(String(d[d.index(periodIndex ?? d.startIndex, offsetBy: 1)...d.index(d.startIndex, offsetBy: d.count - 1)])) + } + + private func parseHTML(html: String, food: String, type: String) -> Any { + + var infoString = "" + + var isPersonalEmpty = true + var personalPlanCount = 0 + var mWebsitePriority = 0 + + do { + let db = try Connection("\(path)/db.sqlite3") + _ = self.createAndClearTables(in: db) + + let substitutionsDocument = try SwiftSoup.parse(html) + let rows = try substitutionsDocument.select("tr") + + let groupPreference = prefs.string(forKey: "classes") + let coursePreference = prefs.string(forKey: "courses") for i in (0.. 2 && mDate[...mDate.index(mDate.startIndex, offsetBy: 2)] == "psa" { - personalSubst.append(SubstModel(group: mGroup, course: mCourse, additional: mAdditional, - date: mDate, time: mTime, room: mRoom, teacher: mTeacher, type: mType)) - let insertPersonal = personal.insert(group <- mGroup, course <- mCourse, additional <- mAdditional, - date <- mDate, time <- mTime, room <- mRoom, teacher <- mTeacher, substType <- mType) - try db.run(insertPersonal) - } else if courses == nil || courses == "", classes != nil && classes != "" { - if !mGroup.isEmpty && mGroup != "" { - if classes!.contains(mGroup) || mGroup.contains(classes!) { - personalSubst.append(SubstModel(group: mGroup, course: mCourse, additional: mAdditional, - date: mDate, time: mTime, room: mRoom, teacher: mTeacher, type: mType)) - let insertPersonal = personal.insert(group <- mGroup, course <- mCourse, additional <- mAdditional, - date <- mDate, time <- mTime, room <- mRoom, teacher <- mTeacher, substType <- mType) - try db.run(insertPersonal) - isPersonalEmpty = false - personalPlanCount += 1 - } - } - } else if courses != nil && courses != "" && classes != nil && classes != "" { - if mGroup != "" && mCourse != "" { - if courses!.contains(mCourse) { - if classes!.contains(mGroup) || mGroup.contains(classes!) { - personalSubst.append(SubstModel(group: mGroup, course: mCourse, additional: mAdditional, - date: mDate, time: mTime, room: mRoom, teacher: mTeacher, type: mType)) - let insertPersonal = personal.insert(group <- mGroup, course <- mCourse, additional <- mAdditional, - date <- mDate, time <- mTime, room <- mRoom, teacher <- mTeacher, substType <- mType) - try db.run(insertPersonal) - isPersonalEmpty = false - personalPlanCount += 1 - } - } - } + isPSA = true } + let mDatePriority = self.assignDatePriority(for: mDate, isPSA) ?? 0 + let mGroupPriority = self.assignRanking(for: mGroup, isPSA) + + let substitution = SubstModel(group: mGroup, course: mCourse, additional: mAdditional, date: mDate, time: mTime, room: mRoom, teacher: mTeacher, type: mType, groupPriority: mGroupPriority, datePriority: mDatePriority, websitePriority: mWebsitePriority) + + mWebsitePriority += 1 + + try db.run(self.insert(into: substitutions, substitution: substitution)) + + if self.isPersonal(with: groupPreference ?? "", and: coursePreference ?? "", for: substitution) || isPSA { + try db.run(self.insert(into: personal, substitution: substitution)) + if !isPSA { + isPersonalEmpty = false + personalPlanCount += 1 + } + } } + if type == "personal" { personalPlanCount = 0 } + prefs.set(personalPlanCount, forKey: "personalPlanCount") + if isPersonalEmpty { - personalSubst.append(SubstModel(group: "", course: NSLocalizedString("personal_plan_empty", comment: ""), additional: "", date: "", time: "", room: "", teacher: "", type: "")) - let insertPersonal = personal.insert(group <- "", course <- NSLocalizedString("personal_plan_empty", comment: ""), additional <- "", date <- "", time <- "", room <- "", teacher <- "", substType <- "") - try db.run(insertPersonal) + let emptySubstitution = SubstModel(group: "", course: NSLocalizedString("personal_plan_empty", comment: ""), additional: "", date: "", time: "", room: "", teacher: "", type: "", groupPriority: 0, datePriority: 0, websitePriority: 0) + try db.run(self.insert(into: personal, substitution: emptySubstitution)) } - let lastUpdated = try doc.select("h1").get(0).text() - info = "\(NSLocalizedString("last_updated", comment: ""))\(lastUpdated)." - let pi: Elements = try doc.select("p") + // start info fetch + // TODO: better documentation, please - for item in pi { - info += "\n\n\(try item.text())" + let lastUpdated = try substitutionsDocument.select("h1").get(0).text() + infoString = "\(NSLocalizedString("last_updated", comment: ""))\(lastUpdated)." + let informationTableElements = try substitutionsDocument.select("p") + + for item in informationTableElements { + infoString += "\n\n\(try item.text())" } - prefs.set(info.trimmingCharacters(in: .whitespacesAndNewlines), forKey: "information") - } catch {} - - infoList.append(info.trimmingCharacters(in: .whitespacesAndNewlines)) - - do { - let foodDoc: Document = try SwiftSoup.parse(food) - let ef: Elements = try foodDoc.select("th") + prefs.set(infoString.trimmingCharacters(in: .whitespacesAndNewlines), forKey: "information") - let db = try Connection("\(path)/db.sqlite3") + // start food fetch - try db.run(foodmenu.create(ifNotExists: true) { t in - t.column(id, primaryKey: true) - t.column(text) - }) - - try db.run(foodmenu.delete()) + let foodDocument = try SwiftSoup.parse(food) + let foodItems = try foodDocument.select("th") var indices = [Int]() let daysAndVon = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "von"] - for i in 0.. [SubstModel] { + func getSubstitutionsFromDatabase() -> [SubstModel] { var substs = [SubstModel]() do { let db = try Connection("\(path)/db.sqlite3") - for subst in try db.prepare(substitutions) { - substs.append(SubstModel(group: subst[group], course: subst[course], additional: subst[additional], date: subst[date], time: subst[time], room: subst[room], teacher: subst[teacher], type: subst[substType])) + + var table: AnySequence + if !prefs.bool(forKey: "original_sorting") { + table = try db.prepare(substitutions.order(date_priority.asc, date.asc, group_priority.asc, group.asc, time.asc)) + } else { + table = try db.prepare(substitutions.order(website_priority.asc)) } - } catch {} + + for subst in table { + + let substitution = SubstModel(group: subst[group], course: subst[course], additional: subst[additional], date: subst[date], time: subst[time], room: subst[room], teacher: subst[teacher], type: subst[subst_type], groupPriority: Int(subst[group_priority]), datePriority: Int(subst[date_priority]), websitePriority: Int(subst[website_priority])) + + substs.append(substitution) + } + } catch { + } return substs } - func getPersonalFromDatabase() -> [SubstModel] { - var substs = [SubstModel]() + func getPersonalSubstitutionsFromDatabase() -> [SubstModel] { + var personalSubsts = [SubstModel]() do { let db = try Connection("\(path)/db.sqlite3") - for subst in try db.prepare(personal) { - substs.append(SubstModel(group: subst[group], course: subst[course], additional: subst[additional], date: subst[date], time: subst[time], room: subst[room], teacher: subst[teacher], type: subst[substType])) + + var table: AnySequence + if !prefs.bool(forKey: "original_sorting") { + table = try db.prepare(personal.order(date_priority.asc, date.asc, group_priority.asc, group.asc, time.asc)) + } else { + table = try db.prepare(personal.order(website_priority.asc)) } - } catch {} - return substs + + for subst in table { + + let substitution = SubstModel(group: subst[group], course: subst[course], additional: subst[additional], date: subst[date], time: subst[time], room: subst[room], teacher: subst[teacher], type: subst[subst_type], groupPriority: Int(subst[group_priority]), datePriority: Int(subst[date_priority]), websitePriority: Int(subst[website_priority])) + + personalSubsts.append(substitution) + } + } catch { + } + return personalSubsts } func readInformation() -> String { diff --git a/AvH Plan/GeneralPlanViewController.swift b/AvH Plan/GeneralPlanViewController.swift index 00412c6..1d869f1 100644 --- a/AvH Plan/GeneralPlanViewController.swift +++ b/AvH Plan/GeneralPlanViewController.swift @@ -30,7 +30,7 @@ class GeneralViewController: PlanViewController { } override func getFromDatabase() -> [SubstModel] { - return df.getFromDatabase() + return df.getSubstitutionsFromDatabase() } } diff --git a/AvH Plan/PersonalPlanViewController.swift b/AvH Plan/PersonalPlanViewController.swift index 5f9e45f..2a21d01 100644 --- a/AvH Plan/PersonalPlanViewController.swift +++ b/AvH Plan/PersonalPlanViewController.swift @@ -43,7 +43,7 @@ class PersonalPlanViewController: PlanViewController { } override func getFromDatabase() -> [SubstModel] { - return df.getPersonalFromDatabase() + return df.getPersonalSubstitutionsFromDatabase() } override func getIndex() -> Int { diff --git a/AvH Plan/PlanViewController.swift b/AvH Plan/PlanViewController.swift index 2836940..d76d753 100644 --- a/AvH Plan/PlanViewController.swift +++ b/AvH Plan/PlanViewController.swift @@ -91,7 +91,7 @@ class PlanViewController : UICollectionViewController, UICollectionViewDelegateM } func getFromDatabase() -> [SubstModel] { - return self.df.getFromDatabase() + return self.df.getSubstitutionsFromDatabase() } func getRefreshViewString() -> String { @@ -128,8 +128,9 @@ class PlanViewController : UICollectionViewController, UICollectionViewDelegateM } override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath as IndexPath) as! PlanViewCell - var psa = false + let course = self.substs[indexPath.item].course var image = df.getImage(from: course) @@ -149,7 +150,6 @@ class PlanViewController : UICollectionViewController, UICollectionViewDelegateM cell.group.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0) cell.course.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0) cell.additional.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0) - psa = true } else { cell.date.text = self.substs[indexPath.item].date cell.group.textColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1) diff --git a/AvH Plan/SubstModel.swift b/AvH Plan/SubstModel.swift index b95a79c..134f12b 100644 --- a/AvH Plan/SubstModel.swift +++ b/AvH Plan/SubstModel.swift @@ -17,8 +17,11 @@ class SubstModel { var room: String var teacher: String var type: String + var groupPriority: Int + var datePriority: Int + var websitePriority: Int - init(group: String, course: String, additional: String, date: String, time: String, room: String, teacher: String, type: String) { + init(group: String, course: String, additional: String, date: String, time: String, room: String, teacher: String, type: String, groupPriority: Int, datePriority: Int, websitePriority: Int) { self.group = group self.course = course self.additional = additional @@ -27,5 +30,8 @@ class SubstModel { self.room = room self.teacher = teacher self.type = type + self.groupPriority = groupPriority + self.datePriority = datePriority + self.websitePriority = websitePriority } }