// // RestrictionTableViewController.swift // CovidSafe // // Copyright © 2021 Australian Government. All rights reserved. // import UIKit let restrictionSelectedStateKey = "restrictionSelectedStateKey" let restrictionSelectedActivityKey = "restrictionSelectedActivityKey" class RestrictionTableViewController: UITableViewController { @IBOutlet var tableFooterView: UIView! lazy var restrictionSelectedState: StateTerritory = { guard let value = UserDefaults.standard.value(forKey: restrictionSelectedStateKey) as? String else { return StateTerritory.AU } return StateTerritory(rawValue: value)! }(){ didSet { UserDefaults.standard.set(restrictionSelectedState.rawValue, forKey: restrictionSelectedStateKey) } } lazy var restrictionSelectedActivity: JurisdictionalRestrictionActivity? = { guard let value = UserDefaults.standard.value(forKey: restrictionSelectedActivityKey) as? String, !value.isEmpty else { return nil } return value }(){ didSet { UserDefaults.standard.set(restrictionSelectedActivity, forKey: restrictionSelectedActivityKey) } } var stateRestrictions: StateRestriction? var jurisdictionalRestrictionActivities: [JurisdictionalRestrictionActivity] = [] override func viewDidLoad() { super.viewDidLoad() tableView.register(UINib(nibName: "SimpleTableViewCell", bundle: nil), forCellReuseIdentifier: "SimpleTableCell") tableView.register(UINib(nibName: "SelectionTableViewCell", bundle: nil), forCellReuseIdentifier: "SelectionTableCell") tableView.register(UINib(nibName: "TableSectionHeaderView", bundle: nil), forHeaderFooterViewReuseIdentifier: "SectionHeader") // call api if needed if restrictionSelectedState != .AU { getRestrictions(shouldFetchFromApi: true) } else { setupTableFooter() } } // MARK: - Table view data source func reloadTableView() { setupTableFooter() tableView.reloadData() } func setupTableFooter() { tableView.tableFooterView = restrictionSelectedState == .AU || restrictionSelectedActivity == nil ? tableFooterView : nil } override func numberOfSections(in tableView: UITableView) -> Int { if restrictionSelectedState != .AU && restrictionSelectedActivity != nil { // top section for selection, bottom for data from restrictions API return 2 } return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if section == 0 { return restrictionSelectedState == .AU ? 1 : 2 } else { if let selectedActivity = restrictionSelectedActivity, let activities = stateRestrictions?.activities { let activity = activities.first { (activity) -> Bool in return activity.activityTitle == selectedActivity } let hasMainContent = activity?.mainContent != nil && !(activity?.mainContent?.isEmpty ?? true) let includeMainContent = hasMainContent ? 1 : 0 return (activity?.sections?.count ?? 0) + includeMainContent } return 0 } } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { if indexPath.section == 0 { // check if value is present let isValueEmpty = indexPath.row == 0 ? restrictionSelectedState == .AU : restrictionSelectedActivity?.isEmpty ?? true if isValueEmpty { let cell = tableView.dequeueReusableCell(withIdentifier: "SimpleTableCell") as! SimpleTableViewCell cell.title.textColor = UIColor.covidSafeColor cell.rightImageView.image = UIImage(named: "chevron-right-green") cell.rightImageView.isHidden = true configureSimpleCell(cell: cell, row: indexPath.row) cell.selectionStyle = .none return cell } else { let cell = tableView.dequeueReusableCell(withIdentifier: "SelectionTableCell") as! SelectionTableViewCell configureSelectionCell(cell: cell, row: indexPath.row) cell.selectionStyle = .none return cell } } let cell = tableView.dequeueReusableCell(withIdentifier: "SimpleTableCell") as! SimpleTableViewCell cell.title.textColor = UIColor.covidSafeDarkFontColor cell.rightImageView.image = UIImage(named: "ChevronRight") cell.rightImageView.isHidden = false cell.title.text = "" if let selectedActivity = restrictionSelectedActivity { cell.title.text = getSectionTitle(for: selectedActivity, indexPath: indexPath) } return cell } override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { if section == 1 { let sectionHeaderView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "SectionHeader") as! SectionHeaderView guard let selectedActivity = restrictionSelectedActivity, let activity = getActivity(activityName: selectedActivity) else { sectionHeaderView.title.text = "" return sectionHeaderView } let dateFormatter = DateFormatter() dateFormatter.dateStyle = .medium dateFormatter.timeStyle = .short sectionHeaderView.title.text = activity.dateUpdated return sectionHeaderView } return nil } override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { if section == 0 { // returning nil does not suffice return 0 } else { // automatic return -1 } } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if indexPath.section == 1 { // if should show content let contentView = RestrictionDetailsViewController(nibName: "RestrictionsView", bundle: nil) contentView.hideSubtitle = false contentView.hideBackButton = false contentView.titleString = "" contentView.subtitleString = "" contentView.htmlString = "" if let selectedActivity = restrictionSelectedActivity { contentView.titleString = getSectionTitle(for: selectedActivity, indexPath: indexPath) contentView.subtitleString = getSectionSubtitle(for: indexPath) contentView.htmlString = getSectionHtmlContent(for: selectedActivity, indexPath: indexPath) } navigationController?.pushViewController(contentView, animated: true) return } var tableViewController: UITableViewController! if indexPath.row == 0 { // bring up state selections let selectStateTerritoryViewController = SelectableTableViewController() selectStateTerritoryViewController.title = "restrictions_select_state".localizedString() selectStateTerritoryViewController.selectedValue = restrictionSelectedState selectStateTerritoryViewController.data = [getStateValues()] selectStateTerritoryViewController.delegate = self tableViewController = selectStateTerritoryViewController } else if indexPath.row == 1 { // bring up activity selections let selectActivityyViewController = SelectableTableViewController() selectActivityyViewController.title = "restrictions_select_activity".localizedString() selectActivityyViewController.selectedValue = restrictionSelectedActivity selectActivityyViewController.data = [jurisdictionalRestrictionActivities] selectActivityyViewController.delegate = self tableViewController = selectActivityyViewController } let navController = UINavigationController(rootViewController: tableViewController) present(navController, animated: true, completion: nil) } func configureSimpleCell(cell: SimpleTableViewCell, row: Int) { if row == 0 { cell.title.text = "restrictions_select_state".localizedString() } else { cell.title.text = "restrictions_select_activity".localizedString() } } func configureSelectionCell(cell: SelectionTableViewCell, row: Int) { if row == 0 { cell.title.text = "restrictions_state".localizedString() cell.selection.text = restrictionSelectedState.stateTerritoryFullName() } else { cell.selection.text = restrictionSelectedActivity cell.title.text = "restrictions_activity".localizedString() } } //MARK: selectable options func getStateValues() -> [StateTerritory] { return [StateTerritory.ACT, StateTerritory.NSW, StateTerritory.NT, StateTerritory.QLD, StateTerritory.SA, StateTerritory.TAS, StateTerritory.VIC, StateTerritory.WA] } //MARK: data retrieval fileprivate func getSectionTitle(for selectedActivity: JurisdictionalRestrictionActivity, indexPath: IndexPath) -> String { guard let activity = getActivity(activityName: selectedActivity) else { return "" } let hasMainContent = activity.mainContent != nil && !activity.mainContent!.isEmpty if hasMainContent && indexPath.row == 0 { return "main_restrictions".localizedString() } let indexOffset = hasMainContent ? -1 : 0 guard let activitySections = activity.sections, activitySections.count > (indexPath.row + indexOffset) else { return "" } return activitySections[indexPath.row + indexOffset].title ?? "" } fileprivate func getSectionHtmlContent(for selectedActivity: JurisdictionalRestrictionActivity, indexPath: IndexPath) -> String? { guard let activity = getActivity(activityName: selectedActivity) else { return nil } let hasMainContent = activity.mainContent != nil && !activity.mainContent!.isEmpty if hasMainContent && indexPath.row == 0 { return activity.mainContent } let indexOffset = hasMainContent ? -1 : 0 guard let activitySections = activity.sections, activitySections.count > (indexPath.row + indexOffset) else { return nil } return activitySections[indexPath.row + indexOffset].content ?? nil } fileprivate func getSectionSubtitle(for indexPath: IndexPath) -> String { return "\(restrictionSelectedState.rawValue) - \(restrictionSelectedActivity ?? "")" } fileprivate func getActivity(activityName: JurisdictionalRestrictionActivity) -> RestrictionsActivity? { if let activities = stateRestrictions?.activities { let activity = activities.first { (activity) -> Bool in return activity.activityTitle == activityName } return activity } return nil } } // MARK: Selected state territory delegate extension RestrictionTableViewController: TableSelectionDelegate { func didChangeSelectedValue(selectedValue: Any) { var didChangeState = false if let value = selectedValue as? StateTerritory { didChangeState = restrictionSelectedState != value restrictionSelectedState = value restrictionSelectedActivity = nil } if let value = selectedValue as? JurisdictionalRestrictionActivity { restrictionSelectedActivity = value } getRestrictions(shouldFetchFromApi: didChangeState || stateRestrictions == nil) } } extension RestrictionTableViewController { fileprivate func getRestrictions(shouldFetchFromApi: Bool) { guard restrictionSelectedState != .AU, shouldFetchFromApi else { // reload to reflect selections in the table reloadTableView() return } // call API RestrictionsAPI.getRestrictions(forState: restrictionSelectedState) { (restrictionsResponse, error) in guard error == nil else { // handle api error let errorVC = CSGenericErrorViewController(nibName: "CSGenericErrorView", bundle: nil) errorVC.errorViewModel = CSGenericErrorViewModel(errorTitle: "restrictions_error_heading".localizedString(), errorContentDescription: "restrictions_error_message".localizedString(), mainButtonLabel: "restrictions_error_try".localizedString(), mainButtonCallback: { self.getRestrictions(shouldFetchFromApi: true) }, secondaryButtonLabel: "restrictions_error_dismiss".localizedString(), secondaryButtonCallback: nil) self.present(errorVC, animated: true, completion: nil) return } self.stateRestrictions = restrictionsResponse self.retrieveActivities() self.reloadTableView() } } fileprivate func retrieveActivities() { guard let restrictions = stateRestrictions, let activities = restrictions.activities else { return } jurisdictionalRestrictionActivities = [] for activity in activities { if let activityName = activity.activityTitle { jurisdictionalRestrictionActivities.append(activityName) } } } } class SimpleTableViewCell: UITableViewCell { @IBOutlet weak var title: UILabel! @IBOutlet weak var rightImageView: UIImageView! } class SelectionTableViewCell: UITableViewCell { @IBOutlet weak var title: UILabel! @IBOutlet weak var selection: UILabel! } class SectionHeaderView: UITableViewHeaderFooterView { @IBOutlet weak var title: UILabel! }