diff --git a/2023 Update Notes.pdf b/2023 Update Notes.pdf new file mode 100644 index 0000000..6f1ef9f Binary files /dev/null and b/2023 Update Notes.pdf differ diff --git a/Documentation for republishing an IOS app (get it back into the Appstore).pdf b/Documentation for republishing an IOS app (get it back into the Appstore).pdf new file mode 100644 index 0000000..1f04343 Binary files /dev/null and b/Documentation for republishing an IOS app (get it back into the Appstore).pdf differ diff --git a/Info.plist b/Info.plist index ca6bde3..1a66e74 100644 --- a/Info.plist +++ b/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.1 CFBundleVersion - 2 + 4 LSRequiresIPhoneOS NSCameraUsageDescription diff --git a/QRScannerViewController.swift b/QRScannerViewController.swift index a521606..f630fbe 100644 --- a/QRScannerViewController.swift +++ b/QRScannerViewController.swift @@ -108,9 +108,8 @@ AVCaptureMetadataOutputObjectsDelegate { if captureSession.inputs.count == 0 { setupSession() //needed for camera permissions } - //self.captureSession.startRunning() // If they arrive on the scanner, they have come back from the main container – and need to (re)scan. - if captureSession?.isRunning == false { + if captureSession.isRunning == false { captureSession.startRunning() //needed to run the camera } } @@ -146,7 +145,7 @@ AVCaptureMetadataOutputObjectsDelegate { AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate)) found(code: stringValue, completion: { (success) in if success == true { - self.performSegue(withIdentifier: "PresentMainContainer", sender: nil) + self.performSegue(withIdentifier: "PresentMainContainer", sender: nil) //program crashes here } else { self.captureSession.startRunning() diff --git a/SettingsViewController.swift b/SettingsViewController.swift index 91e9591..9c6271b 100644 --- a/SettingsViewController.swift +++ b/SettingsViewController.swift @@ -83,8 +83,8 @@ extension SettingsViewController: UITableViewDataSource, UITableViewDelegate { var labelText = "" switch indexPath.row { - case 0: - labelText = "Scan new QR code" + /*case 0: + labelText = "Scan new QR code"*/ case 1: labelText = "Refresh event data now" case 2: @@ -108,9 +108,10 @@ extension SettingsViewController: UITableViewDataSource, UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { switch indexPath.row { - case 0: + /*case 0: loadDevEvents = 0 - navigationController?.pushViewController(QRScannerViewController.init(), animated: true) + navigationController?.pushViewController(QRScannerViewController.init(), animated: true)*/ + case 1: if loadDevEvents == 1 { loadDevEvents += 1 diff --git a/SidebarTableViewController.swift b/SidebarTableViewController.swift new file mode 100644 index 0000000..b9d8fd9 --- /dev/null +++ b/SidebarTableViewController.swift @@ -0,0 +1,226 @@ +// +// SidebarTableViewController.swift +// iOSEventApp +// +// Created by Nathaniel Brown on 3/6/18. +// Copyright © 2018 LightSys. All rights reserved. +// + +import UIKit + +protocol MenuDelegate:AnyObject { + func switchTo(vcName: String, entityNameForData: String?, informationPageName pageName: String?) + func swipedToClose() +} + +/// Inserts padding around an Image +extension UIImage { + + func addImagePadding(x: CGFloat, y: CGFloat) -> UIImage? { + let width: CGFloat = size.width + x + let height: CGFloat = size.height + y + UIGraphicsBeginImageContextWithOptions(CGSize(width: width, height: height), false, 0) + let origin: CGPoint = CGPoint(x: (width - size.width) / 2, y: (height - size.height) / 2) + draw(at: origin) + let imageWithPadding = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + + return imageWithPadding + } +} + +/** + Loads the SidebarAppearances and tells the RootViewController what view controller to load with what data. + */ +class SidebarTableViewController: UITableViewController { + + weak var menuDelegate: MenuDelegate? + + var themes: [Theme]? + var _variableSidebarItems = [SidebarAppearance]() + var variableSidebarItems: [SidebarAppearance] { + get { + return _variableSidebarItems + } + set { + _variableSidebarItems = newValue + tableView.reloadData() + tableView.separatorStyle = UITableViewCell.SeparatorStyle.none + } + } + + func loadSidebarItemsIfNeeded() { + guard variableSidebarItems.count == 0 else { + return + } + reloadSidebarItems() + } + + func reloadSidebarItems() { + let container = (UIApplication.shared.delegate as! AppDelegate).persistentContainer + let loader = DataController(newPersistentContainer: container) + themes = loader.fetchAllObjects(onContext: container.viewContext, forName: "Theme") as? [Theme] + let context = container.viewContext + + let sidebarItems = (loader.fetchAllObjects(onContext: context, forName: "SidebarAppearance") + as! [SidebarAppearance]).sorted(by: { (item1, item2) -> Bool in + return item1.order! < item2.order! + }) + variableSidebarItems = sidebarItems + + if let data = (loader.fetchAllObjects(onContext: context, forName: "General")?.first as? General)?.logo, let imageData = Data(base64Encoded: data) { + let image = UIImage(data: imageData) + let imageView = UIImageView(image: image?.addImagePadding(x: 150, y: 100)) + // Shrink image view's width (and keep aspect ratio) + let maxWidth = view.frame.size.width + if imageView.frame.size.width > maxWidth { + imageView.frame.size.height *= maxWidth / imageView.frame.size.width + imageView.frame.size.width = maxWidth + } + // Shrink image view's height (and keep aspect ratio) + let maxHeight: CGFloat = 160 + if imageView.frame.size.height > maxHeight { + imageView.frame.size.width *= maxHeight / imageView.frame.size.height + imageView.frame.size.height = maxHeight + } + // To prevent the image view from stretching and provide a background. + let containingView = UIView(frame: CGRect(x: 0, y: 0, width: maxWidth, height: imageView.frame.size.height)) + + // Background + let background = CAGradientLayer() + background.colors = getThemeColors() + // Make the gradient horizontal instead of vertical + background.transform = CATransform3DMakeRotation(CGFloat.pi / 2, 0, 0, 1) + background.frame = containingView.frame // Must come after the transform + + // Add views and layers + containingView.layer.addSublayer(background) + containingView.addSubview(imageView) + tableView.tableHeaderView = containingView + } + else { + tableView.tableHeaderView = nil + } + + tableView.reloadData() + } + + @IBAction func swipedLeft(_ sender: Any) { + menuDelegate?.swipedToClose() + } + + // MARK: - Table view data source + + override func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + guard variableSidebarItems.count > 0 else { + return 3 // Welcome, About, Settings + } + // Welcome not shown + return variableSidebarItems.count + 3 // About, Settings, and Map are constant + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + switch indexPath.row { + case 0...(variableSidebarItems.count == 0 ? 0 : variableSidebarItems.count-1): + if variableSidebarItems.count > 0 { + if variableSidebarItems[indexPath.row].category == "Notifications" { + menuDelegate?.switchTo(vcName: "notifications", entityNameForData: nil, informationPageName: nil) + } + else if variableSidebarItems[indexPath.row].category == "ContactPage" { + menuDelegate?.switchTo(vcName: "contacts", entityNameForData: nil, informationPageName: nil) + } + else if variableSidebarItems[indexPath.row].category == "Housing" { + menuDelegate?.switchTo(vcName: "housing", entityNameForData: "HousingUnit", informationPageName: nil) + } + else if variableSidebarItems[indexPath.row].category == "Schedule" { + menuDelegate?.switchTo(vcName: "schedule", entityNameForData: "ScheduleDay", informationPageName: nil) + } + else if variableSidebarItems[indexPath.row].category == "PrayerPartners" { + menuDelegate?.switchTo(vcName: "prayerPartners", entityNameForData: "PrayerPartnerGroup", informationPageName: nil) + } + else { + menuDelegate?.switchTo(vcName: "informationPage", entityNameForData: "InformationPage", informationPageName: variableSidebarItems[indexPath.row].nav) + } + } else { + menuDelegate?.switchTo(vcName: "welcome", entityNameForData: nil, informationPageName: nil) + } + case variableSidebarItems.count, 1: + // Case one is covered earlier if data is loaded. By default switch statements don't fall through in swift. + menuDelegate?.switchTo(vcName: "about", entityNameForData: nil, informationPageName: nil) + case variableSidebarItems.count + 1, 2: + menuDelegate?.switchTo(vcName: "settings", entityNameForData: nil, informationPageName: nil) + default: + // Map is always at index 3 or greater + menuDelegate?.switchTo(vcName: "welcome", entityNameForData: nil, informationPageName: nil) + } + tableView.deselectRow(at: indexPath, animated: true) + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + + let cell = tableView.dequeueReusableCell(withIdentifier: "sidebarCell", for: indexPath) as! SidebarTableViewCell + + let row = indexPath.row + if row < variableSidebarItems.count { + cell.sideImageView.image = UIImage(named: variableSidebarItems[row].icon!) + cell.label.text = variableSidebarItems[row].nav! + } + else if row == 0 { + // Only if data isn't loaded + cell.sideImageView.image = UIImage(named: "ic_camera") + cell.label.text = "Welcome" + } + else if row == variableSidebarItems.count || row == 1 { + // After welcome or all variable items + cell.sideImageView.image = UIImage(named: "ic_info") + cell.label.text = "About" + } + else if row == variableSidebarItems.count + 1 || row == 2 { + // Settings + cell.sideImageView.image = UIImage(named: "settingsIcon") + cell.label.text = "Settings" + } + else { + // Map (if data loaded) + cell.sideImageView.image = UIImage(named: "ic_camera") + cell.label.text = "Scan QR Code" + } + // set cell color to light theme + cell.contentView.backgroundColor = UIColor(cgColor: getThemeColors()[0]) + return cell + } + + func getThemeColors() -> [CGColor] { + let themeArray: [Theme]? = themes + // set default values + var result: [CGColor] = [UIColor(red: 0x60/256.0, green: 0x80/256.0, blue: 0xC0/256.0, alpha: 1).cgColor, UIColor(red: 0x30/256.0, green: 0x40/256.0, blue: 0x60/256.0, alpha: 1).cgColor] + for theme in themeArray ?? [] { + if (theme.themeName == "themeColor") { + let themeRGB: String = String((theme.themeValue?.split(separator: "#")[0])!) + let greenStartIdx = themeRGB.index(themeRGB.startIndex, offsetBy: 2) + let blueStartIdx = themeRGB.index(greenStartIdx, offsetBy: 2) + let themeRed:Int = Int(String(themeRGB[..