diff --git a/AvH Plan.xcodeproj/project.pbxproj b/AvH Plan.xcodeproj/project.pbxproj index ef59257..eaa3929 100644 --- a/AvH Plan.xcodeproj/project.pbxproj +++ b/AvH Plan.xcodeproj/project.pbxproj @@ -97,7 +97,7 @@ A96D4CC722DDE01A006BAB34 /* GeneralPlanViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralPlanViewController.swift; sourceTree = ""; }; A96D4CC922DDE184006BAB34 /* PersonalPlanViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonalPlanViewController.swift; sourceTree = ""; }; A9769079233F2E680015AF1A /* CoursePickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoursePickerViewController.swift; sourceTree = ""; }; - A996BFF322E05AAB00E7BE42 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Base; path = Base.lproj/Info.plist; sourceTree = ""; }; + A996BFF322E05AAB00E7BE42 /* Base */ = {isa = PBXFileReference; explicitFileType = text.html; name = Base; path = Base.lproj/Info.plist; sourceTree = ""; }; A996BFFC22E05AAB00E7BE42 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; A996BFFD22E05AAB00E7BE42 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = ""; }; A99AB5F7230155DE00555295 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; diff --git a/AvH Plan/Base.lproj/Info.plist b/AvH Plan/Base.lproj/Info.plist index 3cd084d..aaa6cd0 100644 --- a/AvH Plan/Base.lproj/Info.plist +++ b/AvH Plan/Base.lproj/Info.plist @@ -53,5 +53,9 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + LSApplicationQueriesSchemes + + youtube + diff --git a/AvH Plan/Base.lproj/LaunchScreen.storyboard b/AvH Plan/Base.lproj/LaunchScreen.storyboard index 879ed5e..fd51fde 100644 --- a/AvH Plan/Base.lproj/LaunchScreen.storyboard +++ b/AvH Plan/Base.lproj/LaunchScreen.storyboard @@ -23,10 +23,10 @@ - - - - + + + + diff --git a/AvH Plan/Base.lproj/Main.storyboard b/AvH Plan/Base.lproj/Main.storyboard index c92a58d..cc29d79 100644 --- a/AvH Plan/Base.lproj/Main.storyboard +++ b/AvH Plan/Base.lproj/Main.storyboard @@ -74,9 +74,11 @@ @@ -138,8 +140,10 @@ @@ -265,6 +269,7 @@ + @@ -286,6 +291,16 @@ + + + + + + + + + + @@ -338,7 +353,7 @@ - + diff --git a/AvH Plan/ColourPickerView.swift b/AvH Plan/ColourPickerView.swift index da13d2c..5f0b21a 100644 --- a/AvH Plan/ColourPickerView.swift +++ b/AvH Plan/ColourPickerView.swift @@ -21,7 +21,6 @@ class ColourPickerView: UIViewController, UICollectionViewDataSource, UICollecti var index = 0 var key = "" @IBOutlet weak var collectionView: UICollectionView! - var previousSelected: IndexPath? = nil var currentSelected: IndexPath? = nil var selectedNewItem = false diff --git a/AvH Plan/CustomizationViewController.swift b/AvH Plan/CustomizationViewController.swift index d0b57ea..2e25019 100644 --- a/AvH Plan/CustomizationViewController.swift +++ b/AvH Plan/CustomizationViewController.swift @@ -12,6 +12,7 @@ class CustomizationViewController: UITableViewController, UITextFieldDelegate { let prefs = UserDefaults.standard let df = DataFetcher.sharedInstance + var buttonTextChanged = false @IBOutlet weak var txtName: UITextField! @IBOutlet weak var txtClasses: UITextField! @@ -20,6 +21,7 @@ class CustomizationViewController: UITableViewController, UITextFieldDelegate { @IBOutlet weak var textToolbar: UIToolbar! @IBOutlet weak var orderingSegments: UISegmentedControl! @IBOutlet weak var autoRefreshToggle: UISwitch! + @IBOutlet weak var customizeCourseColorsButton: UIButton! @IBAction func textDismissButton(_ sender: UIBarButtonItem) { view.endEditing(true) @@ -42,17 +44,11 @@ class CustomizationViewController: UITableViewController, UITextFieldDelegate { } @IBAction func done(_ sender: UIBarButtonItem) { - self.prefs.set(self.txtName.text, forKey: "username") self.prefs.set(self.txtClasses.text, forKey: "classes") self.prefs.set(self.txtCourses.text, forKey: "courses") - var defaultPlan: Int - if self.defaultSwitch.isOn { - defaultPlan = 1 - } else { - defaultPlan = 0 - } + let defaultPlan = self.defaultSwitch.isOn ? 1 : 0 self.prefs.set(defaultPlan, forKey: "default-plan") self.prefs.set(self.orderingSegments.selectedSegmentIndex == 1, forKey: "original_sorting") self.prefs.set(self.autoRefreshToggle.isOn, forKey: "auto_refresh") @@ -66,6 +62,34 @@ class CustomizationViewController: UITableViewController, UITextFieldDelegate { } } + @IBAction func longPressListener(_ sender: UILongPressGestureRecognizer) { + sender.minimumPressDuration = 2 + if sender.state == .ended { + if !buttonTextChanged { + self.customizeCourseColorsButton.setTitle(NSLocalizedString("made_by_deniz", comment: ""), for: .normal) + buttonTextChanged = true + } else { + self.customizeCourseColorsButton.setTitle(NSLocalizedString("customize_course_colors", comment: ""), for: .normal) + buttonTextChanged = false + } + } + } + + @IBAction func infoLongPressListener(_ sender: UILongPressGestureRecognizer) { + sender.minimumPressDuration = 2 + if sender.state == .ended { + let youtubeId = "Jc2xfYuLWgE" + if let youtubeURL = URL(string: "youtube://\(youtubeId)"), + UIApplication.shared.canOpenURL(youtubeURL) { + // redirect to app + UIApplication.shared.open(youtubeURL, options: [:], completionHandler: nil) + } else if let youtubeURL = URL(string: "https://www.youtube.com/watch?v=\(youtubeId)") { + // redirect through safari + UIApplication.shared.open(youtubeURL, options: [:], completionHandler: nil) + } + } + } + override func viewDidLoad() { super.viewDidLoad() @@ -76,17 +100,8 @@ class CustomizationViewController: UITableViewController, UITextFieldDelegate { self.txtName.text = prefs.string(forKey: "username") self.txtClasses.text = prefs.string(forKey: "classes") self.txtCourses.text = prefs.string(forKey: "courses") - if self.prefs.integer(forKey: "default-plan") == 1 { - self.defaultSwitch.isOn = true - } else { - self.defaultSwitch.isOn = false - } - var order: Int - if self.prefs.bool(forKey: "original_sorting") { - order = 1 - } else { - order = 0 - } + self.defaultSwitch.isOn = self.prefs.integer(forKey: "default-plan") == 1 ? true : false + let order = self.prefs.bool(forKey: "original_sorting") ? 1 : 0 self.orderingSegments.selectedSegmentIndex = order self.autoRefreshToggle.isOn = self.prefs.bool(forKey: "auto_refresh") } diff --git a/AvH Plan/DataFetcher.swift b/AvH Plan/DataFetcher.swift index 82d6f68..1440a42 100644 --- a/AvH Plan/DataFetcher.swift +++ b/AvH Plan/DataFetcher.swift @@ -140,7 +140,7 @@ class DataFetcher { let a = String(group[...group.startIndex]) if group.count > 1, let b = Int(String(group[group.index(group.startIndex, offsetBy: 0)...group.index(group.startIndex, offsetBy: 1)])) { return -b - } else if self.checkStringForArray(s: a, checking: juniors) == true { + } else if self.checkStringForArray(s: a, checking: juniors, lowercase: false) == true { return -101 } else { return -100 @@ -154,6 +154,8 @@ class DataFetcher { if isPSA { return -1 + } else if d.isEmpty { + return 13 } let periodIndex = d.firstIndex(of: ".") @@ -244,9 +246,9 @@ class DataFetcher { let foodItems = try foodDocument.select("th") var indices = [Int]() - let daysAndVon = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "von"] + let daysAndVon = ["montag", "dienstag", "mittwoch", "donnerstag", "freitag", "von", "wünschen"] for i in 0.. Bool { + private func checkStringForArray(s: String, checking: [String], lowercase: Bool) -> Bool { + let str = lowercase ? s.lowercased() : s for i in checking.indices { - if s.contains(checking[i]) { + if str.contains(checking[i]) { return true } } diff --git a/AvH Plan/MenuViewController.swift b/AvH Plan/MenuViewController.swift index a06bf68..151aa50 100644 --- a/AvH Plan/MenuViewController.swift +++ b/AvH Plan/MenuViewController.swift @@ -65,7 +65,7 @@ class MenuViewController : UICollectionViewController, UICollectionViewDelegateM df.doAsync(do: "menu") { menuItems in self.items = menuItems as! [String] - DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { + UIView.performWithoutAnimation { self.collectionView.reloadData() } diff --git a/AvH Plan/PlanViewController.swift b/AvH Plan/PlanViewController.swift index 534c5a7..efb60cf 100644 --- a/AvH Plan/PlanViewController.swift +++ b/AvH Plan/PlanViewController.swift @@ -76,11 +76,12 @@ class PlanViewController : UICollectionViewController, UICollectionViewDelegateM self.substs = self.getFromDatabase() self.collectionView.reloadData() - if self.df.shouldRefresh { + if self.df.shouldRefresh || (self.prefs.bool(forKey: "setup_finished") && !self.prefs.bool(forKey: "first_refresh")) { self.collectionView.setContentOffset(CGPoint(x: 0, y: -self.refreshControl.frame.size.height), animated: true) self.refreshControl.beginRefreshing() self.refreshControl.sendActions(for: .valueChanged) self.df.shouldRefresh = false + self.prefs.set(true, forKey: "first_refresh") } } @@ -111,7 +112,9 @@ class PlanViewController : UICollectionViewController, UICollectionViewDelegateM @objc private func objDoAsync(_ sender: Any) { self.df.doAsync(do: self.getViewType()) { substitutions in self.substs = substitutions as! [SubstModel] - self.collectionView.reloadData() + UIView.performWithoutAnimation { + self.collectionView.reloadData() + } self.refreshControl.endRefreshing() self.df.setTabBarBadge(for: self.tabBarController?.tabBar.items) } diff --git a/AvH Plan/de.lproj/Localizable.strings b/AvH Plan/de.lproj/Localizable.strings index 05fd6da..bebab90 100644 --- a/AvH Plan/de.lproj/Localizable.strings +++ b/AvH Plan/de.lproj/Localizable.strings @@ -80,6 +80,8 @@ "enter_grade_title" = "Wie du deine Klasse eintragen kannst"; "enter_course_title" = "Wie du deine Kurse eintragen kannst"; "enter_order_title" = "Informationen über Sortierweisen"; -"enter_grade_help" = "Trage deine derzeitige Klasse ein, damit sie in deinem persönlichen Plan auftaucht.\n\nAnmerkung:\n\nIn der Mittelstufe müssen Nummer und Buchstabe zusammen geschrieben werden, Beispiel: \"5a\".\n\nIn der E-Phase müssen diese durch ein Leerzeichen getrennt werden, Beispiel: \"18 a\".\n\nIn der Q1/Q2 sollen nur die Nummern eingetragen werden, Beispiel: \"17\".\n\nMehrere Klassen können nur eingetragen werden, wenn keine Kurse eingetragen sind."; +"enter_grade_help" = "Trage deine derzeitige Klasse ein, damit sie in deinem persönlichen Plan auftaucht.\n\nAnmerkung:\n\nIn der Mittelstufe müssen Nummer und Buchstabe zusammen geschrieben werden, Beispiel: \"5a\".\n\nIn der E-Phase müssen diese durch ein Leerzeichen getrennt werden, Beispiel: \"18 a\".\n\nIn der Q1/Q2 sollen nur die Nummern eingetragen werden, Beispiel: \"17\".\n\nMehrere Klassen einzutragen ist nicht empfohlen."; "enter_course_help" = "Trag die Kürzel für die Kurse ein, welche in deinem persönlichen Plan auftauchen sollen. Du kannst diese auf deinem Stundenplan finden.\n\nHier sind einige Beispiele:\n\nMathe in der 5. Klasse (Mittelstufe) wäre MAT.\n\nDer Englisch-Profilkurs in der E-Phase könnte ENP1 sein.\n\nDer Bio-Grundkurs in der Q1 ist z.B. bio1.\n\nMeist müssen Kurse für Mittelstufenschüler nicht eingetragen werden.\nTrenne mehrere Kurse mit Leerzeichen, Kommas sind optional.\nGroß- und Kleinschreibung wird beachtet."; "enter_order_help" = "Du kannst zwischen zwei Sortierweisen auswählen, welche die Reihenfolge der Einträge auf dem Vertretungsplan bestimmen.\n\nStandardmäßig ist \'App-Sortierung\' ausgewählt; dies bietet einen konsistenten Plan sortiert nach Klassen, dann nach Stunden.\n\n\'Website-Sortierung\' bietet die Original-Reihenfolge der Website. Diese ist jedoch nicht konsistent, weswegen \'App-Sortierung\' standardmäßig ausgewählt ist."; +"made_by_deniz" = "Entwickelt von Deniz :)"; +"customize_course_colors" = "Kursfarben einstellen"; diff --git a/AvH Plan/de.lproj/Main.strings b/AvH Plan/de.lproj/Main.strings index 8d19eaf..18af7c9 100644 --- a/AvH Plan/de.lproj/Main.strings +++ b/AvH Plan/de.lproj/Main.strings @@ -130,9 +130,9 @@ "oiQ-2o-sH8.text" = "Bei App-Start aktualisieren"; -"jng-S6-ZuJ.normalTitle" = "Stelle Kursfarben ein"; +"jng-S6-ZuJ.normalTitle" = "Kursfarben einstellen"; -"bj2-hB-vVb.title" = "Benutzerdefinierte Farben"; +"bj2-hB-vVb.title" = "Kursfarben"; "FhN-ih-qVW.title" = "Speichern"; diff --git a/AvH Plan/en.lproj/Localizable.strings b/AvH Plan/en.lproj/Localizable.strings index 888da95..794d8ce 100644 --- a/AvH Plan/en.lproj/Localizable.strings +++ b/AvH Plan/en.lproj/Localizable.strings @@ -81,6 +81,8 @@ "enter_grade_title" = "How to enter your grade"; "enter_course_title" = "How to enter your courses"; "enter_order_title" = "Information on ordering systems"; -"enter_grade_help" = "Enter your current grade to have it appear in your personal plan.\n\nNote:\n\nIn junior phase, put the number and letter together, as in \"5a\".\n\nIn E-Phase, separate them by a space, as in \"18 a\".\n\nIn Q1/Q2, only put in the number, as in \"17\".\n\nMultiple grades can only be entered when no courses have been entered."; +"enter_grade_help" = "Enter your current grade to have it appear in your personal plan.\n\nNote:\n\nIn junior phase, put the number and letter together, as in \"5a\".\n\nIn E-Phase, separate them by a space, as in \"18 a\".\n\nIn Q1/Q2, only put in the number, as in \"17\".\n\nEntering multiple grades is not recommended."; "enter_course_help" = "You need to enter the course abbreviation for every course you want in your personal plan. You can find them on your time table.\n\nHere\'s a few examples:\n\nMathematics in 5th grade (juniors) would be MAT.\n\nAdvanced English in E-Phase (seniors) for the English profile may be ENP1.\n\nBasic Biology in Q1 could be bio1.\n\nIn most cases, entering courses while in junior phase is redundant.\nSeparate multiple courses by spaces, commas are optional.\nCapitalisation is required."; "enter_order_help" = "You may pick between two ordering systems that dictate the order in which the items on the substitution plan will appear in.\n\nThe default \'app order\' is an algorithm implemented in this app that provides a consistently-sorted substitution plan ordered just like the substitution plan on the website used to; sorted by classes, then by time.\n\n\'Website order\' offers the items on the substitution plan just like they\'re presented on the school website, but since these are not guaranteed to be consistent, \'app order\' is picked by default."; +"made_by_deniz" = "Developed by Deniz :)"; +"customize_course_colors" = "Customize course colors"; diff --git a/AvH PlanTests/Info.plist b/AvH PlanTests/Info.plist index 8f4b015..685c12f 100644 --- a/AvH PlanTests/Info.plist +++ b/AvH PlanTests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.0 + 1.0.0 CFBundleVersion 1 UILaunchStoryboardName