mobile-ios/CovidSafe/RestrictionTableViewController.swift

380 lines
15 KiB
Swift
Raw Normal View History

2021-02-26 03:41:20 +00:00
//
// 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<StateTerritory>()
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<JurisdictionalRestrictionActivity>()
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!
}