Improve tableview display

master
Laurent 6 years ago
parent d2b6f539f1
commit f64ac3ed27
  1. 2
      TournamentStats.xcodeproj/project.pbxproj
  2. 60
      TournamentStats/Base.lproj/Main.storyboard
  3. 63
      TournamentStats/UI/DataSourceWrapper.swift
  4. 2
      TournamentStats/UI/StackTableCell.swift
  5. 86
      TournamentStats/UI/components/DataSourceWrapper.swift
  6. 23
      TournamentStats/UI/components/PieChart.swift
  7. 3
      TournamentStats/UI/reports/InfographyView.swift
  8. 7
      TournamentStats/report/structures/CountryCounter.swift
  9. 14
      TournamentStats/report/structures/CumulatedResults.swift
  10. 18
      TournamentStats/report/structures/CumulatedWins.swift
  11. 10
      TournamentStats/report/structures/PlayerResult.swift
  12. 7
      TournamentStats/report/structures/TournamentCounter.swift
  13. 10
      TournamentStats/report/structures/TournamentRepresentable.swift
  14. 4
      TournamentStats/report/structures/TournamentStats.swift
  15. 10
      TournamentStats/report/structures/TournamentWinner.swift
  16. 18
      TournamentStats/utils/ColumnRepresentable.swift

@ -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;

@ -143,7 +143,6 @@
<!--Infography View Controller-->
<scene sceneID="e9y-X1-vaX">
<objects>
<placeholder placeholderIdentifier="IBFirstResponder" id="yr4-1K-87y" userLabel="First Responder" sceneMemberID="firstResponder"/>
<viewController storyboardIdentifier="container" id="mxo-2c-VBS" customClass="InfographyViewController" customModule="TournamentStats" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Eky-dM-hcs">
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
@ -152,8 +151,65 @@
<viewLayoutGuide key="safeArea" id="sco-HF-vLG"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="yr4-1K-87y" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-1297" y="665"/>
</scene>
<!--Table View Controller-->
<scene sceneID="nN4-jC-y8e">
<objects>
<tableViewController id="SvX-cb-F4l" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="qfc-Fg-ig2">
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="pIa-Td-YmF">
<rect key="frame" x="0.0" y="28" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="pIa-Td-YmF" id="4sR-9u-Rvr">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.666666666666664"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SA0-Y7-9tl">
<rect key="frame" x="54.999999999999986" y="0.0" width="187.66666666666663" height="43.666666666666664"/>
<color key="backgroundColor" red="0.99942404029999998" green="0.98555368190000003" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="caN-Kr-4mB">
<rect key="frame" x="0.0" y="0.0" width="55" height="43.666666666666664"/>
<color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="55" id="aXB-vb-F3x"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="SA0-Y7-9tl" secondAttribute="bottom" id="0S7-uH-xeg"/>
<constraint firstItem="SA0-Y7-9tl" firstAttribute="top" secondItem="4sR-9u-Rvr" secondAttribute="top" id="6WK-bE-7u9"/>
<constraint firstItem="SA0-Y7-9tl" firstAttribute="leading" secondItem="caN-Kr-4mB" secondAttribute="trailing" id="X1C-rB-2RJ"/>
<constraint firstItem="caN-Kr-4mB" firstAttribute="leading" secondItem="4sR-9u-Rvr" secondAttribute="leading" id="X2f-pv-Mxd"/>
<constraint firstItem="SA0-Y7-9tl" firstAttribute="width" secondItem="4sR-9u-Rvr" secondAttribute="width" multiplier="0.5" id="XAH-CL-eMW"/>
<constraint firstItem="caN-Kr-4mB" firstAttribute="top" secondItem="4sR-9u-Rvr" secondAttribute="top" id="iCQ-gs-pai"/>
<constraint firstAttribute="bottom" secondItem="caN-Kr-4mB" secondAttribute="bottom" id="ukI-XR-xnu"/>
</constraints>
</tableViewCellContentView>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="SvX-cb-F4l" id="T14-S7-Nvx"/>
<outlet property="delegate" destination="SvX-cb-F4l" id="6bK-cC-iSP"/>
</connections>
</tableView>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="IX9-Je-AO2" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-879" y="638"/>
<point key="canvasLocation" x="-426" y="879"/>
</scene>
</scenes>
<inferredMetricsTieBreakers>

@ -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<T : ColumnRepresentable> : 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
}
}

@ -15,7 +15,7 @@ class StackTableCell: UITableViewCell {
override func awakeFromNib() {
self.backgroundColor = UIColor.clear
self.stackView.distribution = .fillEqually
self.stackView.distribution = .equalSpacing
}
}

@ -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<T : ColumnRepresentable> : 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
}
}

@ -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) {

@ -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)

@ -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)"

@ -10,12 +10,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
var numberOfCashes: Int = 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)"]
}

@ -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]
}

@ -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,

@ -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)")

@ -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,

@ -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 []
}

@ -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,

@ -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: "</td><td>")
let all = self.columnDescriptors().map { $0.header }.joined(separator: "</td><td>")
return "<tr class=\"table-header\"><td>\(all)</td></tr>"
}
func html() -> String {
let all = self.colums().joined(separator: "</td><td>")
let all = self.cellValues().joined(separator: "</td><td>")
return "<tr><td>\(all)</td></tr>"
}

Loading…
Cancel
Save