mobile-ios/CovidSafe/CovidStatisticsViewController.swift

594 lines
25 KiB
Swift
Raw Permalink Normal View History

2020-09-14 01:23:11 +00:00
//
// CovidStatisticsViewController.swift
// CovidSafe
//
// Copyright © 2020 Australian Government. All rights reserved.
//
import UIKit
import Lottie
class CovidStatisticsViewController: UITableViewController {
2020-10-16 04:45:07 +00:00
private let showHideStatisticsKey = "showHideStatisticsKey"
2020-09-14 01:23:11 +00:00
private let heartImage = UIImage(named: "heart")
private let virusMoleculeImage = UIImage(named: "virus-molecule")
private let trendUpImage = UIImage(named: "trending-up")
2021-02-02 00:04:43 +00:00
private let alertTriangleImage = UIImage(named: "alert-triangle")
2020-09-14 01:23:11 +00:00
private var statisticsUpdatedDate: Date?
private var showError: Bool = false
private var showInternetError: Bool = false
private var showRefresh: Bool = false
2020-10-16 04:45:07 +00:00
lazy var showStatistics: Bool = {
guard let value = UserDefaults.standard.value(forKey: showHideStatisticsKey) as? Bool else {
return true
}
return value
}(){
didSet {
UserDefaults.standard.set(showStatistics, forKey: showHideStatisticsKey)
}
}
2021-02-02 00:04:43 +00:00
private lazy var statisticForStateTerritory: StateTerritory = {
guard let value = UserDefaults.standard.string(forKey: statisticsStateTerritorySelectedKey) else {
return StateTerritory.AU
}
return StateTerritory(rawValue: value)!
}()
2020-09-14 01:23:11 +00:00
2021-02-02 00:04:43 +00:00
private var statisticsData: StatisticsResponse?
2020-09-14 01:23:11 +00:00
private var statisticSections: [[StatisticRowModel]] = []
var statisticsDelegate: StatisticsDelegate?
2021-02-02 00:04:43 +00:00
var homeDelegate: HomeDelegate?
var contentSizeKVOToken: NSKeyValueObservation?
2020-09-14 01:23:11 +00:00
var isLoading = false {
didSet {
reloadTable()
}
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.isScrollEnabled = false
2021-02-02 00:04:43 +00:00
tableView.register(UINib(nibName: "ExternalLinkTableViewCell", bundle: nil), forCellReuseIdentifier: "ExternalLinkTableViewCell")
2020-09-14 01:23:11 +00:00
tableView.register(UINib(nibName: "StatDetailedCell", bundle: nil), forCellReuseIdentifier: "StatDetailedCell")
tableView.register(UINib(nibName: "MainStatisticsHeader", bundle: nil), forCellReuseIdentifier: "MainStatisticsHeader")
tableView.register(UINib(nibName: "StatisticsTableHeader", bundle: nil), forCellReuseIdentifier: "StatisticsHeader")
tableView.register(UINib(nibName: "LoadingViewCell", bundle: nil), forCellReuseIdentifier: "LoadingViewCell")
2021-02-02 00:04:43 +00:00
getStatistics()
2020-09-14 01:23:11 +00:00
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
2021-02-02 00:04:43 +00:00
contentSizeKVOToken = tableView.observe(\.contentSize, options: .new) { (tableView, change) in
if let newsize = change.newValue {
self.statisticsDelegate?.setStatisticsContainerHeight(height: newsize.height)
}
}
2020-09-14 01:23:11 +00:00
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
2021-02-02 00:04:43 +00:00
contentSizeKVOToken?.invalidate()
2020-09-14 01:23:11 +00:00
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?){
if(keyPath == "contentSize"){
if let newvalue = change?[.newKey]{
let newsize = newvalue as! CGSize
statisticsDelegate?.setStatisticsContainerHeight(height: newsize.height)
}
}
}
2021-02-02 00:04:43 +00:00
// MARK: Retrieve Statistics from API
func getStatistics() {
if showStatistics {
isLoading = true
StatisticsAPI.getStatistics(forState: statisticForStateTerritory) { (stats, error) in
let hasInternet = self.homeDelegate?.isInternetReachable() ?? false
if error != nil {
switch error {
case .TokenExpiredError:
self.homeDelegate?.showTokenExpiredMessage()
default:
// do nothing special
break
}
}
self.isLoading = false
self.setupData(statistics: stats, errorType: error, hasInternet: hasInternet)
}
}
}
2020-09-14 01:23:11 +00:00
// MARK: Process data for the table
2020-11-10 00:51:00 +00:00
func setupData(statistics: StatisticsResponse?, errorType: CovidSafeAPIError?, hasInternet: Bool) {
2020-09-14 01:23:11 +00:00
showInternetError = false
showError = false
showRefresh = false
if errorType != nil {
showError = true
showRefresh = true
}
if !hasInternet {
showInternetError = true
}
2021-02-02 00:04:43 +00:00
statisticsData = statistics
processData(statisticsData: statisticsData, forState: statisticForStateTerritory)
2020-09-14 01:23:11 +00:00
reloadTable()
}
2021-02-02 00:04:43 +00:00
fileprivate func processData(statisticsData: StatisticsResponse?, forState: StateTerritory) {
2020-09-14 01:23:11 +00:00
statisticSections = []
guard let statisticsData = statisticsData else {
// this is the edge case of no data available.
// need an empty section to render the main header
statisticSections.append([])
return
}
// Set updated date
if let updatedDate = statisticsData.updatedDate {
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX") // set locale to reliable US_POSIX
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
statisticsUpdatedDate = dateFormatter.date(from:updatedDate)
}
var mainSectionData: [StatisticRowModel] = []
2021-02-02 00:04:43 +00:00
let nationalData = statisticsData.national
2020-09-14 01:23:11 +00:00
2021-02-02 00:04:43 +00:00
if statisticsData.version() == 2 {
var stateData = statisticsData.national
switch forState {
case .ACT:
stateData = statisticsData.act
case .NSW:
stateData = statisticsData.nsw
case .NT:
stateData = statisticsData.nt
case .SA:
stateData = statisticsData.sa
case .TAS:
stateData = statisticsData.tas
case .VIC:
stateData = statisticsData.vic
case .WA:
stateData = statisticsData.wa
case .QLD:
stateData = statisticsData.qld
default:
stateData = statisticsData.national
}
let descriptionFormat = "%@\r\r%@"
// New cases section
let newCases = stateData?.newCases ?? 0
let localCases = stateData?.newLocallyAcquired ?? 0
let overseasCases = stateData?.newOverseasAcquired ?? 0
2021-07-05 04:11:27 +00:00
let underInvestigation = stateData?.newUnderInvestigation ?? 0
var bottomDesc = "\(String.localizedStringWithFormat("locally_acquired".localizedString(), "\(localCases)"))\r\(String.localizedStringWithFormat( "overseas_acquired".localizedString(), "\(overseasCases)"))\r\(String.localizedStringWithFormat( "under_investigation".localizedString(), "\(underInvestigation)"))"
2021-02-02 00:04:43 +00:00
var description = String.localizedStringWithFormat(descriptionFormat, "new_cases".localizedString(), bottomDesc)
var attributedDesc = NSMutableAttributedString(string: description)
attributedDesc.addAttribute(.font,
value: UIFont.preferredFont(for: .callout, weight: .semibold),
range: NSRange(description.range(of: "\(localCases)")!, in: description))
attributedDesc.addAttribute(.font,
value: UIFont.preferredFont(for: .callout, weight: .semibold),
range: NSRange(description.range(of: "\(overseasCases)")!, in: description))
2021-07-05 04:11:27 +00:00
attributedDesc.addAttribute(.font,
value: UIFont.preferredFont(for: .callout, weight: .semibold),
range: NSRange(description.range(of: "\(underInvestigation)")!, in: description))
2021-02-02 00:04:43 +00:00
mainSectionData.append(StatisticRowModel(number: newCases, description: attributedDesc, image: trendUpImage))
// Active cases section
let activeCases = stateData?.activeCases ?? 0
let totalDeaths = stateData?.deaths ?? 0
bottomDesc = String.localizedStringWithFormat("total_deaths".localizedString(), "\(totalDeaths)")
description = String.localizedStringWithFormat(descriptionFormat, "active_cases".localizedString(), bottomDesc)
attributedDesc = NSMutableAttributedString(string: description)
attributedDesc.addAttribute(.font,
value: UIFont.preferredFont(for: .callout, weight: .semibold),
range: NSRange(description.range(of: "\(totalDeaths)")!, in: description))
mainSectionData.append(StatisticRowModel(number: activeCases, description: attributedDesc, image: virusMoleculeImage))
statisticSections.append(mainSectionData)
} else {
// we keep old design/data shown in case the response does not have state based data
if let cases = nationalData?.newCases {
mainSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "new_cases".localizedString()), image: trendUpImage))
}
if let cases = nationalData?.totalCases {
mainSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "total_confirmed_cases".localizedString()), image: virusMoleculeImage))
}
if let cases = nationalData?.recoveredCases {
mainSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "recovered".localizedString()), image: heartImage))
}
if let cases = nationalData?.deaths {
mainSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "deaths".localizedString()), image: virusMoleculeImage, imageBackgroundColor: UIColor.covidSafeLightGreyColor))
}
statisticSections.append(mainSectionData)
var statesSectionData: [StatisticRowModel] = []
if let cases = statisticsData.act?.totalCases {
statesSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "australian_capital_territory".localizedString())))
}
if let cases = statisticsData.nsw?.totalCases {
statesSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "new_south_wales".localizedString())))
}
if let cases = statisticsData.nt?.totalCases {
statesSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "northern_territory".localizedString())))
}
if let cases = statisticsData.qld?.totalCases {
statesSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "queensland".localizedString())))
}
if let cases = statisticsData.sa?.totalCases {
statesSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "south_australia".localizedString())))
}
if let cases = statisticsData.tas?.totalCases {
statesSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "tasmania".localizedString())))
}
if let cases = statisticsData.vic?.totalCases {
statesSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "victoria".localizedString())))
}
if let cases = statisticsData.wa?.totalCases {
statesSectionData.append(StatisticRowModel(number: cases, description: NSAttributedString(string: "western_australia".localizedString())))
}
if statesSectionData.count > 0 {
statisticSections.append(statesSectionData)
}
2020-09-14 01:23:11 +00:00
}
}
// MARK: Table view delegate
fileprivate func reloadTable() {
tableView.reloadData()
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if isLoading {
return nil
}
if section == 0 {
let headerView = tableView.dequeueReusableCell(withIdentifier: "MainStatisticsHeader") as! MainStatisticsHeaderViewCell
headerView.statisticsDelegate = statisticsDelegate
2020-10-16 04:45:07 +00:00
headerView.statisticsTableDelegate = self
2021-02-02 00:04:43 +00:00
let shouldDisplayStateSelection = (statisticsData?.version() ?? 0) >= 2
2020-10-16 04:45:07 +00:00
let hideShowLabel = showStatistics ? "hide".localizedString() : "show".localizedString()
headerView.hideShowButton.setTitle(hideShowLabel, for: .normal)
2021-02-02 00:04:43 +00:00
headerView.selectStateTerritoryContainer.isHidden = !showStatistics || !shouldDisplayStateSelection
2020-09-14 01:23:11 +00:00
2021-02-02 00:04:43 +00:00
headerView.titleLabel.text = (statisticForStateTerritory == StateTerritory.AU || !shouldDisplayStateSelection) ? "national_numbers".localizedString() : String.localizedStringWithFormat(
"state_number_heading".localizedString(),
statisticForStateTerritory.rawValue
)
2020-10-16 04:45:07 +00:00
if let updateDate = statisticsUpdatedDate, showStatistics {
2020-09-14 01:23:11 +00:00
let dateFormatter = DateFormatter()
2020-10-16 04:45:07 +00:00
dateFormatter.dateStyle = .medium
dateFormatter.timeStyle = .short
headerView.dateLabelContainer.isHidden = false
headerView.dateLabelDivider.isHidden = false
2021-06-10 00:27:37 +00:00
headerView.dateLabel.text = String.localizedStringWithFormat("latest_case_numbers".localizedString(), dateFormatter.string(from: updateDate))
2020-09-14 01:23:11 +00:00
} else {
2020-10-16 04:45:07 +00:00
headerView.dateLabelContainer.isHidden = true
headerView.dateLabelDivider.isHidden = true
2020-09-14 01:23:11 +00:00
}
if showInternetError {
headerView.errorLabel.text = "numbers_no_internet".localizedString()
} else {
headerView.errorLabel.text = "numbers_error".localizedString()
}
2020-10-16 04:45:07 +00:00
headerView.errorLabel.isHidden = !showError || !showStatistics
headerView.refreshViewContainer.isHidden = !showRefresh || !showStatistics
2020-09-14 01:23:11 +00:00
return headerView
}
if section == 1 {
let headerView = tableView.dequeueReusableCell(withIdentifier: "StatisticsHeader")
return headerView
}
return nil
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if isLoading {
return 0 // no header for section
}
return -1 // automatic
}
2020-10-16 04:45:07 +00:00
override func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
2020-09-14 01:23:11 +00:00
if isLoading {
2020-10-16 04:45:07 +00:00
return 0 // no header for section
}
return 53
}
override func numberOfSections(in tableView: UITableView) -> Int {
if isLoading || !showStatistics {
2020-09-14 01:23:11 +00:00
return 1
}
return statisticSections.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isLoading {
return 1
}
2020-10-16 04:45:07 +00:00
if !showStatistics {
return 0
}
2020-09-14 01:23:11 +00:00
return statisticSections[section].count
}
override func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if let loadingCell = cell as? LoadingViewCell {
loadingCell.stopAnimation()
}
}
2020-10-16 04:45:07 +00:00
override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
UIView.performWithoutAnimation {
view.layoutIfNeeded()
}
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
UIView.performWithoutAnimation {
cell.layoutIfNeeded()
}
}
2020-09-14 01:23:11 +00:00
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if isLoading {
let cellView = tableView.dequeueReusableCell(withIdentifier: "LoadingViewCell", for: indexPath) as! LoadingViewCell
cellView.startAnimation()
return cellView
}
// detailed stat row
if indexPath.section == 0 {
let rowData = statisticSections[indexPath.section][indexPath.row]
2021-02-02 00:04:43 +00:00
if rowData.cellType == .Link {
let cellView = tableView.dequeueReusableCell(withIdentifier: "ExternalLinkTableViewCell", for: indexPath) as! ExternalLinkTableViewCell
cellView.cellImage.image = rowData.image
cellView.linkDescription.attributedText = rowData.description
cellView.externalLinkURL = rowData.urlLink
return cellView
2020-09-14 01:23:11 +00:00
} else {
2021-02-02 00:04:43 +00:00
let cellView = tableView.dequeueReusableCell(withIdentifier: "StatDetailedCell", for: indexPath) as! StatDetailedViewCell
cellView.statImage?.image = rowData.image
cellView.statDescription.attributedText = rowData.description
cellView.statNumberLabel.text = NumberFormatter.localizedString(from: NSNumber(value: rowData.number), number: .decimal)
if #available(iOS 11.0, *) {
cellView.statNumberLabel.font = UIFont.preferredFont(for: .largeTitle, weight: .semibold)
} else {
// Fallback on earlier versions
cellView.statNumberLabel.font = UIFont.preferredFont(for: .title1, weight: .semibold)
}
if let bkgColor = rowData.imageBackgroundColor {
cellView.imageBackgroundColor = bkgColor
}
return cellView
2020-09-14 01:23:11 +00:00
}
}
// Simple stat row
var cellView = tableView.dequeueReusableCell(withIdentifier: "StatSummaryCell")
if cellView == nil {
cellView = UITableViewCell(style: .value1, reuseIdentifier: "StatSummaryCell")
cellView?.textLabel?.font = UIFont.preferredFont(forTextStyle: .callout)
cellView?.textLabel?.textColor = UIColor.covidSafeDarkFontColor
cellView?.detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .callout)
cellView?.detailTextLabel?.textColor = UIColor.covidSafeDarkFontColor
}
let rowData = statisticSections[indexPath.section][indexPath.row]
2021-02-02 00:04:43 +00:00
cellView!.textLabel?.attributedText = rowData.description
2020-09-14 01:23:11 +00:00
cellView!.detailTextLabel?.text = NumberFormatter.localizedString(from: NSNumber(value: rowData.number), number: .decimal)
return cellView!
}
}
2020-10-16 04:45:07 +00:00
// MARK: Statistics Table Delegate Implementation
extension CovidStatisticsViewController: StatisticsTableDelegate {
func toggleDisplayStatistics() {
showStatistics = !showStatistics
if showStatistics && statisticSections.count == 0 {
2021-02-02 00:04:43 +00:00
refreshStatistics()
2020-10-16 04:45:07 +00:00
} else {
UIView.transition(with: tableView,
duration: 0.3,
options: .transitionCrossDissolve,
animations: { self.reloadTable() })
}
}
2021-02-02 00:04:43 +00:00
func refreshStatistics() {
getStatistics()
}
func changeStateTerritoryStatistics() {
2021-02-26 03:41:20 +00:00
let selectStateTerritoryViewController = SelectableTableViewController<StateTerritory>()
selectStateTerritoryViewController.selectedValue = statisticForStateTerritory
selectStateTerritoryViewController.data = [[StateTerritory.AU], getStateValues()]
selectStateTerritoryViewController.sectionTitles = ["", "states_territories".localizedString()
]
2021-02-02 00:04:43 +00:00
selectStateTerritoryViewController.delegate = self
let navController = UINavigationController(rootViewController: selectStateTerritoryViewController)
present(navController, animated: true, completion: nil)
}
2021-02-26 03:41:20 +00:00
func getStateValues() -> [StateTerritory] {
return [StateTerritory.ACT,
StateTerritory.NSW,
2021-03-18 03:16:35 +00:00
StateTerritory.NT,
2021-02-26 03:41:20 +00:00
StateTerritory.QLD,
StateTerritory.SA,
StateTerritory.TAS,
StateTerritory.VIC,
StateTerritory.WA]
}
2021-02-02 00:04:43 +00:00
}
// MARK: Selected state territory delegate
2021-02-26 03:41:20 +00:00
extension CovidStatisticsViewController: TableSelectionDelegate {
2021-02-02 00:04:43 +00:00
2021-02-26 03:41:20 +00:00
func didChangeSelectedValue(selectedValue: Any) {
guard let selectedState = selectedValue as? StateTerritory else {
return
}
UserDefaults.standard.set(selectedState.rawValue, forKey: statisticsStateTerritorySelectedKey)
2021-02-02 00:04:43 +00:00
statisticForStateTerritory = selectedState
getStatistics()
}
2020-10-16 04:45:07 +00:00
}
2020-09-14 01:23:11 +00:00
// MARK: Table view cells
class StatDetailedViewCell: UITableViewCell {
@IBOutlet weak var statImage: UIImageView!
@IBOutlet weak var statNumberLabel: UILabel!
@IBOutlet weak var statDescription: UILabel!
@IBOutlet weak var imageContainer: UIView!
var imageBackgroundColor: UIColor? {
didSet {
imageContainer.backgroundColor = imageBackgroundColor
}
}
}
class MainStatisticsHeaderViewCell: UITableViewCell {
@IBOutlet weak var dateLabel: UILabel!
2020-10-16 04:45:07 +00:00
@IBOutlet weak var dateLabelContainer: UIView!
@IBOutlet weak var dateLabelDivider: UIView!
2020-09-14 01:23:11 +00:00
@IBOutlet weak var errorLabel: UILabel!
@IBOutlet weak var refreshViewContainer: UIView!
@IBOutlet weak var titleLabel: UILabel!
2020-10-16 04:45:07 +00:00
@IBOutlet weak var hideShowButton: UIButton!
2021-02-02 00:04:43 +00:00
@IBOutlet weak var selectStateLabel: UILabel!
@IBOutlet weak var selectStateTerritoryContainer: UIStackView!
2020-09-14 01:23:11 +00:00
var statisticsDelegate: StatisticsDelegate?
2020-10-16 04:45:07 +00:00
var statisticsTableDelegate: StatisticsTableDelegate?
2020-09-14 01:23:11 +00:00
2021-02-02 00:04:43 +00:00
override func awakeFromNib() {
super.awakeFromNib()
titleLabel.font = UIFont.preferredFont(for: .title3, weight: .semibold)
let selectStateTerritoryTapGesture = UITapGestureRecognizer(target: self, action: #selector(selectStateTerritoryTapped))
selectStateLabel.addGestureRecognizer(selectStateTerritoryTapGesture)
let selectStateText = NSMutableAttributedString(string: "select_state_territory_button".localizedString(),
attributes: [.font: UIFont.preferredFont(forTextStyle: .callout),
.underlineStyle: NSUnderlineStyle.single.rawValue])
selectStateLabel.attributedText = selectStateText
}
2020-09-14 01:23:11 +00:00
@IBAction func refreshButtonTapped(_ sender: Any) {
2021-02-02 00:04:43 +00:00
statisticsTableDelegate?.refreshStatistics()
2020-09-14 01:23:11 +00:00
}
2020-10-16 04:45:07 +00:00
@IBAction func showHideButtonTapped(_ sender: Any) {
statisticsTableDelegate?.toggleDisplayStatistics()
2021-02-02 00:04:43 +00:00
selectStateTerritoryContainer.isHidden = !selectStateTerritoryContainer.isHidden
}
@IBAction func selectStateTerritoryTapped(_ sender: Any) {
statisticsTableDelegate?.changeStateTerritoryStatistics()
2020-10-16 04:45:07 +00:00
}
2020-09-14 01:23:11 +00:00
}
class LoadingViewCell: UITableViewCell {
@IBOutlet weak var loadingAnimationView: UIView!
var lottieLoadingView: AnimationView?
func startAnimation() {
if lottieLoadingView == nil {
let loadingAnimation = AnimationView(name: "Spinner_upload")
loadingAnimation.loopMode = .loop
loadingAnimation.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: loadingAnimationView.frame.size)
loadingAnimationView.addSubview(loadingAnimation)
lottieLoadingView = loadingAnimation
}
lottieLoadingView?.play()
}
func stopAnimation() {
lottieLoadingView?.stop()
}
}
// MARK: Statistics delegate
2020-10-16 04:45:07 +00:00
protocol StatisticsTableDelegate {
func toggleDisplayStatistics()
2021-02-02 00:04:43 +00:00
func changeStateTerritoryStatistics()
func refreshStatistics()
2020-10-16 04:45:07 +00:00
}
2020-09-14 01:23:11 +00:00
protocol StatisticsDelegate {
func setStatisticsContainerHeight(height: CGFloat)
}
// MARK: Statistics row model
2021-02-02 00:04:43 +00:00
enum StatisticCellType {
case Link, Detail
}
2020-09-14 01:23:11 +00:00
struct StatisticRowModel {
var number: Int
2021-02-02 00:04:43 +00:00
var description: NSAttributedString
2020-09-14 01:23:11 +00:00
var image: UIImage?
var imageBackgroundColor: UIColor?
2021-02-02 00:04:43 +00:00
var urlLink: URL?
var cellType: StatisticCellType?
2020-09-14 01:23:11 +00:00
}