From f64ac3ed271e4f3ad56f552de4b796f1293b25c7 Mon Sep 17 00:00:00 2001 From: Laurent Date: Wed, 14 Aug 2019 16:38:19 +0200 Subject: [PATCH] Improve tableview display --- TournamentStats.xcodeproj/project.pbxproj | 2 +- TournamentStats/Base.lproj/Main.storyboard | 60 ++++++++++++- TournamentStats/UI/DataSourceWrapper.swift | 63 -------------- TournamentStats/UI/StackTableCell.swift | 2 +- .../UI/components/DataSourceWrapper.swift | 86 +++++++++++++++++++ TournamentStats/UI/components/PieChart.swift | 23 +++-- .../UI/reports/InfographyView.swift | 3 +- .../report/structures/CountryCounter.swift | 7 +- .../report/structures/CumulatedResults.swift | 16 ++-- .../report/structures/CumulatedWins.swift | 20 +++-- .../report/structures/PlayerResult.swift | 10 ++- .../report/structures/TournamentCounter.swift | 7 +- .../structures/TournamentRepresentable.swift | 10 ++- .../report/structures/TournamentStats.swift | 4 +- .../report/structures/TournamentWinner.swift | 10 ++- .../utils/ColumnRepresentable.swift | 18 ++-- 16 files changed, 224 insertions(+), 117 deletions(-) delete mode 100644 TournamentStats/UI/DataSourceWrapper.swift create mode 100644 TournamentStats/UI/components/DataSourceWrapper.swift diff --git a/TournamentStats.xcodeproj/project.pbxproj b/TournamentStats.xcodeproj/project.pbxproj index 7f7b196..7940728 100644 --- a/TournamentStats.xcodeproj/project.pbxproj +++ b/TournamentStats.xcodeproj/project.pbxproj @@ -494,7 +494,6 @@ 4D97941222F827A5004A2D7F /* reports */, 4DF7608722A3FB96004B0EF1 /* DetailViewController.swift */, 4DF7608522A3FB96004B0EF1 /* MasterViewController.swift */, - 4D39B6F222F8549100625E31 /* DataSourceWrapper.swift */, 4D39B6F422F856EF00625E31 /* StackTableCell.xib */, 4D39B6F622F8573900625E31 /* StackTableCell.swift */, 4D39B6F922F85C3400625E31 /* UIView+Extensions.swift */, @@ -543,6 +542,7 @@ children = ( 4DF78DCD22F9AA3F00C02F73 /* PieChart.swift */, 4DF78DD022F9AADF00C02F73 /* TableView.swift */, + 4D39B6F222F8549100625E31 /* DataSourceWrapper.swift */, 4DF78DD522F9CE7E00C02F73 /* TitleLabel.swift */, ); path = components; diff --git a/TournamentStats/Base.lproj/Main.storyboard b/TournamentStats/Base.lproj/Main.storyboard index 9df85cf..c1c2c6e 100644 --- a/TournamentStats/Base.lproj/Main.storyboard +++ b/TournamentStats/Base.lproj/Main.storyboard @@ -143,7 +143,6 @@ - @@ -152,8 +151,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/TournamentStats/UI/DataSourceWrapper.swift b/TournamentStats/UI/DataSourceWrapper.swift deleted file mode 100644 index 9bad767..0000000 --- a/TournamentStats/UI/DataSourceWrapper.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// Array+UITableDataSource.swift -// TournamentStats -// -// Created by Laurent Morvillier on 05/08/2019. -// Copyright © 2019 Stax River. All rights reserved. -// - -import Foundation -import UIKit - - - - -class DataSourceWrapper : NSObject, UITableViewDataSource, UITableViewDelegate { - - var columnRepresentables: [T] - - init(array: [T]) { - self.columnRepresentables = array - } - - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - print("numberOfRowsInSection = \(self.columnRepresentables.count)") - return self.columnRepresentables.count + 1 // + 1 for header - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! StackTableCell - - var columns: [String] - var font: UIFont - switch indexPath.row { - case 0: - columns = T.headers() - font = UIFont.boldSystemFont(ofSize: 16.0) - default: - let cr = self.columnRepresentables[indexPath.row - 1] - columns = cr.colums() - font = UIFont.systemFont(ofSize: 16.0) - } - - columns.forEach { value in - let label: UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: 50, height: 30)) - label.textColor = UIColor.white - label.backgroundColor = UIColor.clear - label.text = value - label.font = font - cell.stackView.addArrangedSubview(label) - } - - return cell - } - - func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - return 32.0 - } - - func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - return 0.1 - } - -} diff --git a/TournamentStats/UI/StackTableCell.swift b/TournamentStats/UI/StackTableCell.swift index c84d0db..b375bad 100644 --- a/TournamentStats/UI/StackTableCell.swift +++ b/TournamentStats/UI/StackTableCell.swift @@ -15,7 +15,7 @@ class StackTableCell: UITableViewCell { override func awakeFromNib() { self.backgroundColor = UIColor.clear - self.stackView.distribution = .fillEqually + self.stackView.distribution = .equalSpacing } } diff --git a/TournamentStats/UI/components/DataSourceWrapper.swift b/TournamentStats/UI/components/DataSourceWrapper.swift new file mode 100644 index 0000000..1c1ca40 --- /dev/null +++ b/TournamentStats/UI/components/DataSourceWrapper.swift @@ -0,0 +1,86 @@ +// +// Array+UITableDataSource.swift +// TournamentStats +// +// Created by Laurent Morvillier on 05/08/2019. +// Copyright © 2019 Stax River. All rights reserved. +// + +import Foundation +import UIKit + + + + +class DataSourceWrapper : NSObject, UITableViewDataSource, UITableViewDelegate { + + var columnRepresentables: [T] + let columnDescriptors = T.columnDescriptors() + var totalWidthWeigth: CGFloat = 0.0 + + init(array: [T]) { + self.columnRepresentables = array + self.totalWidthWeigth = self.columnDescriptors.map { $0.widthWeight }.reduce(0, +) + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + print("numberOfRowsInSection = \(self.columnRepresentables.count)") + return self.columnRepresentables.count + 1 // + 1 for header + } + + fileprivate let FONTSIZE: CGFloat = 18.0 + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { +// let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! StackTableCell + let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")! + + var cells: [String] + switch indexPath.row { + case 0: + cells = columnDescriptors.map { $0.header } + default: + let cr = self.columnRepresentables[indexPath.row - 1] + cells = cr.cellValues() + } + + var font: UIFont = UIFont.boldSystemFont(ofSize: FONTSIZE) + + var leftAnchor = cell.contentView.leftAnchor + for (index, value) in cells.enumerated() { + + if (indexPath.row > 0) { + font = self.columnDescriptors[index].number ? UIFont.monospacedDigitSystemFont(ofSize: FONTSIZE, weight: UIFont.Weight.regular) : UIFont.systemFont(ofSize: FONTSIZE) + } + + let label: UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: 50, height: 30)) + label.textColor = UIColor.white + label.backgroundColor = UIColor.clear + label.text = value + label.font = font + label.textAlignment = self.columnDescriptors[index].number ? .right : .left + + cell.contentView.addSubview(label) + label.translatesAutoresizingMaskIntoConstraints = false + label.topAnchor.constraint(equalTo: cell.contentView.topAnchor).isActive = true + label.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor).isActive = true + label.leftAnchor.constraint(equalTo: leftAnchor).isActive = true + leftAnchor = label.rightAnchor + + label.backgroundColor = index.isMultiple(of: 2) ? UIColor.clear : UIColor(white: 0.9, alpha: 0.1) + + let multiplier: CGFloat = self.columnDescriptors[index].widthWeight / self.totalWidthWeigth + label.widthAnchor.constraint(equalTo: cell.contentView.widthAnchor, multiplier: multiplier).isActive = true + + } + return cell + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return 36.0 + } + + func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + return 0.1 + } + +} diff --git a/TournamentStats/UI/components/PieChart.swift b/TournamentStats/UI/components/PieChart.swift index cb76934..72895e7 100644 --- a/TournamentStats/UI/components/PieChart.swift +++ b/TournamentStats/UI/components/PieChart.swift @@ -13,20 +13,29 @@ class PieChart : PieChartView { override init(frame: CGRect) { super.init(frame: frame) + self.holeColor = UIColor.clear self.usePercentValuesEnabled = true + self.minOffset = 16.0 + self.holeRadiusPercent = 0 + self.drawEntryLabelsEnabled = false +// self. + self.legend.textColor = UIColor.white self.legend.font = UIFont.systemFont(ofSize: 16.0) self.legend.orientation = .vertical -// self.legend.form = .square -// self.legend.neededHeight = 320.0 + self.legend.form = .circle +// self.legend.neededHeight = 203.0 // self.legend.neededWidth = 300.0 - self.legend.maxSizePercent = 0.2 - self.legend.verticalAlignment = .center +// self.legend.maxSizePercent = 30 // self.legend.horizontalAlignment = .left - - self.holeRadiusPercent = 0.2 - self.drawEntryLabelsEnabled = false + self.legend.verticalAlignment = .bottom + self.legend.drawInside = false +// self.legend.yOffset = -30.0 +// self.legend.xOffset = 10.0 +// self.legend.maxSizePercent = 0.8 +// self.legend. +// self. } required init?(coder aDecoder: NSCoder) { diff --git a/TournamentStats/UI/reports/InfographyView.swift b/TournamentStats/UI/reports/InfographyView.swift index e30e0b6..8c69e45 100644 --- a/TournamentStats/UI/reports/InfographyView.swift +++ b/TournamentStats/UI/reports/InfographyView.swift @@ -65,6 +65,7 @@ class InfographyViewController : UIViewController { let buyinDistribPie = PieChart(frame: CGRect.zero) buyinDistribPie.data = generator.tournamentBuyinDistribution.pieChartData buyinDistribPie.defineConstraints(height: 300) + buyinDistribPie.notifyDataSetChanged() let firstPrizeDistributionPie = PieChart(frame: CGRect.zero) firstPrizeDistributionPie.data = generator.firstPrizeDistribution.pieChartData @@ -72,7 +73,7 @@ class InfographyViewController : UIViewController { let prizepoolDistribPie = PieChart(frame: CGRect.zero) prizepoolDistribPie.data = generator.tournamentPrizepoolDistribution.pieChartData - prizepoolDistribPie.defineConstraints(height: 300) + prizepoolDistribPie.defineConstraints(height: 400) let hstack2: UIStackView = UIStackView(arrangedSubviews: [buyinDistribPie, firstPrizeDistributionPie, prizepoolDistribPie]) hstack2.defineConstraints(width: 1000, height: 350.0) diff --git a/TournamentStats/report/structures/CountryCounter.swift b/TournamentStats/report/structures/CountryCounter.swift index fce2de6..a5fa464 100644 --- a/TournamentStats/report/structures/CountryCounter.swift +++ b/TournamentStats/report/structures/CountryCounter.swift @@ -22,11 +22,12 @@ class CountryCounter : HTMLRepresentable { self.counter += 1 } - static func headers() -> [String] { - return ["Country", "Cashes"] + static func columnDescriptors() -> [ColumnDescriptor] { + return [ColumnDescriptor(header: "Country", number: false, widthWeight: 1.0), + ColumnDescriptor(header: "Cashes", number: true, widthWeight: 1.0)] } - func colums() -> [String] { + func cellValues() -> [String] { let formattedCountry: String if let flagoji = Locale.current.flagoji(from: self.country) { formattedCountry = "\(flagoji) \(self.country)" diff --git a/TournamentStats/report/structures/CumulatedResults.swift b/TournamentStats/report/structures/CumulatedResults.swift index 498cd1d..161b2e0 100644 --- a/TournamentStats/report/structures/CumulatedResults.swift +++ b/TournamentStats/report/structures/CumulatedResults.swift @@ -9,12 +9,6 @@ import Foundation class CumulatedResults : HTMLRepresentable, ColumnRepresentable { - - enum Fields : String, CaseIterable { - case name = "Name" - case earnings = "Total Earnings" - case cashes = "Cashes" - } var player: Player var total: Double = 0.0 @@ -42,11 +36,13 @@ class CumulatedResults : HTMLRepresentable, ColumnRepresentable { } } - static func headers() -> [String] { - return Fields.allCases.map { $0.rawValue } + static func columnDescriptors() -> [ColumnDescriptor] { + return [ColumnDescriptor(header: "Name", number: false, widthWeight: 2.0), + ColumnDescriptor(header: "Total Earnings", number: true, widthWeight: 1.0), + ColumnDescriptor(header: "Cashes", number: true, widthWeight: 1.0)] } - - func colums() -> [String] { + + func cellValues() -> [String] { return [self.player.formattedName, self.total.currencyFormatted, "\(self.numberOfCashes)"] } diff --git a/TournamentStats/report/structures/CumulatedWins.swift b/TournamentStats/report/structures/CumulatedWins.swift index 34748a1..d9461a3 100644 --- a/TournamentStats/report/structures/CumulatedWins.swift +++ b/TournamentStats/report/structures/CumulatedWins.swift @@ -10,11 +10,11 @@ import Foundation class CumulatedWins : HTMLRepresentable, ColumnRepresentable { - enum Fields : String, CaseIterable { - case name = "Name" - case wins = "Wins" - case earnings = "Total Earnings" - } +// enum Fields : String, CaseIterable { +// case name = "Name" +// case wins = "Wins" +// case earnings = "Total Earnings" +// } var player: Player var total: Double = 0.0 @@ -38,11 +38,13 @@ class CumulatedWins : HTMLRepresentable, ColumnRepresentable { } } - static func headers() -> [String] { - return Fields.allCases.map { $0.rawValue } + static func columnDescriptors() -> [ColumnDescriptor] { + return [ColumnDescriptor(header: "Name", number: false, widthWeight: 2.0), + ColumnDescriptor(header: "Wins", number: true, widthWeight: 1.0), + ColumnDescriptor(header: "Total Earnings", number: true, widthWeight: 1.5)] } - - func colums() -> [String] { + + func cellValues() -> [String] { return [self.player.formattedName, "\(self.winsCount)", self.total.currencyFormatted] } diff --git a/TournamentStats/report/structures/PlayerResult.swift b/TournamentStats/report/structures/PlayerResult.swift index 28d98ff..3530726 100644 --- a/TournamentStats/report/structures/PlayerResult.swift +++ b/TournamentStats/report/structures/PlayerResult.swift @@ -13,11 +13,15 @@ struct PlayerResult : HTMLRepresentable { var tournament: Tournament var result: Result - static func headers() -> [String] { - return ["Player", "Place", "Earnings", "#", "Event"] + static func columnDescriptors() -> [ColumnDescriptor] { + return [ColumnDescriptor(header: "Player", number: false, widthWeight: 1.0), + ColumnDescriptor(header: "Place", number: true, widthWeight: 1.0), + ColumnDescriptor(header: "Earnings", number: true, widthWeight: 1.0), + ColumnDescriptor(header: "#", number: true, widthWeight: 0.2), + ColumnDescriptor(header: "Event", number: false, widthWeight: 1.0)] } - func colums() -> [String] { + func cellValues() -> [String] { return [ self.result.player?.formattedName ?? "", self.result.rank.rankFormatted, diff --git a/TournamentStats/report/structures/TournamentCounter.swift b/TournamentStats/report/structures/TournamentCounter.swift index 6a9482b..50328c9 100644 --- a/TournamentStats/report/structures/TournamentCounter.swift +++ b/TournamentStats/report/structures/TournamentCounter.swift @@ -22,11 +22,12 @@ class DistributionCounter : HTMLRepresentable { self.counter += 1 } - static func headers() -> [String] { - return ["Tournament", "Counter"] + static func columnDescriptors() -> [ColumnDescriptor] { + return [ColumnDescriptor(header: "Tournament", number: false, widthWeight: 2.0), + ColumnDescriptor(header: "Counter", number: true, widthWeight: 1.0)] } - func colums() -> [String] { + func cellValues() -> [String] { var strings: [String] = [] strings.append(self.name) strings.append("\(self.counter)") diff --git a/TournamentStats/report/structures/TournamentRepresentable.swift b/TournamentStats/report/structures/TournamentRepresentable.swift index 99c6519..326857d 100644 --- a/TournamentStats/report/structures/TournamentRepresentable.swift +++ b/TournamentStats/report/structures/TournamentRepresentable.swift @@ -12,11 +12,15 @@ struct TournamentRepresentable : HTMLRepresentable { var tournament: Tournament - static func headers() -> [String] { - return ["#", "Buy-in", "Event", "Prizepool", "Entries"] + static func columnDescriptors() -> [ColumnDescriptor] { + return [ColumnDescriptor(header: "#", number: true, widthWeight: 0.2), + ColumnDescriptor(header: "Buy-in", number: true, widthWeight: 1.0), + ColumnDescriptor(header: "Event", number: false, widthWeight: 1.0), + ColumnDescriptor(header: "Prizepool", number: true, widthWeight: 1.0), + ColumnDescriptor(header: "Entries", number: true, widthWeight: 1.0)] } - func colums() -> [String] { + func cellValues() -> [String] { return [ "\(tournament.number)", tournament.buyin.currencyFormatted, diff --git a/TournamentStats/report/structures/TournamentStats.swift b/TournamentStats/report/structures/TournamentStats.swift index 786b88b..a8ab6f3 100644 --- a/TournamentStats/report/structures/TournamentStats.swift +++ b/TournamentStats/report/structures/TournamentStats.swift @@ -15,11 +15,11 @@ struct TournamentStats : HTMLRepresentable { var prizepool: Double var itmValue: Double - static func headers() -> [String] { + func cellValues() -> [String] { return [] } - func colums() -> [String] { + static func columnDescriptors() -> [ColumnDescriptor] { return [] } diff --git a/TournamentStats/report/structures/TournamentWinner.swift b/TournamentStats/report/structures/TournamentWinner.swift index 8884fee..1ec253a 100644 --- a/TournamentStats/report/structures/TournamentWinner.swift +++ b/TournamentStats/report/structures/TournamentWinner.swift @@ -13,11 +13,15 @@ struct TournamentWinner : HTMLRepresentable { var tournament: Tournament var result: Result - static func headers() -> [String] { - return ["#", "Buy-in", "Event", "Player", "Prize"] + static func columnDescriptors() -> [ColumnDescriptor] { + return [ColumnDescriptor(header: "#", number: true, widthWeight: 0.2), + ColumnDescriptor(header: "Buy-in", number: true, widthWeight: 1.0), + ColumnDescriptor(header: "Event", number: false, widthWeight: 1.0), + ColumnDescriptor(header: "Player", number: false, widthWeight: 1.0), + ColumnDescriptor(header: "Prize", number: true, widthWeight: 1.0)] } - func colums() -> [String] { + func cellValues() -> [String] { return ["\(tournament.number)", tournament.buyin.currencyFormatted, tournament.name, diff --git a/TournamentStats/utils/ColumnRepresentable.swift b/TournamentStats/utils/ColumnRepresentable.swift index bccde4f..0fe82a7 100644 --- a/TournamentStats/utils/ColumnRepresentable.swift +++ b/TournamentStats/utils/ColumnRepresentable.swift @@ -25,9 +25,15 @@ extension UIColor { } -public protocol ColumnRepresentable { - static func headers() -> [String] - func colums() -> [String] +struct ColumnDescriptor { + var header: String + var number: Bool = false + var widthWeight: CGFloat = 1.0 +} + +protocol ColumnRepresentable { + static func columnDescriptors() -> [ColumnDescriptor] + func cellValues() -> [String] var chartDataEntry: ChartDataEntry { get } var pieChartDataEntry: PieChartDataEntry { get } } @@ -80,7 +86,7 @@ extension Array where Element : ColumnRepresentable { } -public protocol HTMLRepresentable : ColumnRepresentable { +protocol HTMLRepresentable : ColumnRepresentable { static func htmlHeaders() -> String func html() -> String } @@ -88,12 +94,12 @@ public protocol HTMLRepresentable : ColumnRepresentable { extension HTMLRepresentable { static func htmlHeaders() -> String { - let all = self.headers().joined(separator: "") + let all = self.columnDescriptors().map { $0.header }.joined(separator: "") return "\(all)" } func html() -> String { - let all = self.colums().joined(separator: "") + let all = self.cellValues().joined(separator: "") return "\(all)" }