TrainViewController.swift 10.5 KB
//
//  TrainViewController.swift
//  Twear
//
//  Created by yangbin on 2021/11/25.
//

import UIKit
import Charts
import SwiftDate

class TrainViewController: UIViewController, DateSegmentViewDelegate, RangeSliderDelegate, ChartViewDelegate {
    
    @IBOutlet weak var dateSegmentView: DateSegmentView!
    @IBOutlet weak var barChartView: BarChartView!
    @IBOutlet weak var sliderView: RangeSliderView!
    @IBOutlet weak var dateLabel: UILabel!
    @IBOutlet weak var trainLabel: UILabel!
    @IBOutlet weak var tableView: UITableView!
    
    var identifierDic: [String: String] = [:]
    private var selectedDate = Date()
    private var barWidth: Double = 1.0/60.0
    private struct TrainPoint {
        var point: Double = 0
        var type: TrainType = .running
        var length: Int = 0
        var date: Date
        var typeStr: String
    }
    private var points: [TrainPoint] = []
    
    private var trainArray: [TrainModel] = [] {
        didSet {
            points = []
            if trainArray.count == 0 {
                resetLabel()
            }
            let max = trainArray.max{$0.calorie < $1.calorie}?.calorie
            if max == 0 {
                barChartView.leftAxis.axisMaximum = 10
            } else {
                barChartView.leftAxis.axisMaximum = Double(max ?? 10000) * 1.1 / 1000
            }
            self.tableView.reloadData()
        }
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        
    }
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        BluetoothManager.shared.getTrainHistoryData(day: .today) {[weak self] train, error in
            if error == 2000 || error == nil {
                self?.updateTodayData()
//                self?.didSelectedDate(date: DateInRegion((self?.selectedDate)!, region: .current), dateType: .day)
            }
        }
    }
    func updateTodayData() {
        if selectedDate.isToday {
            self.tableView.reloadData()
            self.didSelectedDate(date: DateInRegion(self.selectedDate, region: .current), dateType: .day)
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        dateSegmentView.dateTypeView.isHidden = true
        dateSegmentView.delegate = self
        sliderView.delegate = self
        
        view.layoutIfNeeded()
        setupChartView()
        didSelectedDate(date: DateInRegion(), dateType: .day)
//        tableView.register(UINib.init(nibName: "SubTrainCell", bundle: Bundle.main), forCellReuseIdentifier: "SubTrainCell")
        tableView.contentInset = UIEdgeInsets.init(top: 0, left: 0, bottom: 10, right: 0)
        

        // Do any additional setup after loading the view.
    }
    
    
    //MARK: DateSegmentViewDelegate
    func didSelectedDate(date: DateInRegion, dateType: DateType) {
        selectedDate = date.date
        trainArray = TrainModel.getTrainByDay(selectedDate)

//        let t3 = TrainModel(type: .running, date: DateInRegion().date-280.minutes, length: 10*60, calorie: 200, mileage: 300, steps: 500)
//        let t2 = TrainModel(type: .swimming, date: DateInRegion().date-300.minutes, length: 10*60, calorie: 600, mileage: 300, steps: 500)
//        let t1 = TrainModel(type: .sit_up, date: DateInRegion().date-500.minutes, length: 10*60, calorie: 1000, mileage: 300, steps: 500)
//        let t4 = TrainModel(type: .volleyball, date: DateInRegion().date-520.minutes, length: 20*60, calorie: 200, mileage: 300, steps: 500)
//        let t5 = TrainModel(type: .badminton, date: DateInRegion().date-550.minutes, length: 20*60, calorie: 200, mileage: 300, steps: 500)
//        let t6 = TrainModel(type: .basketball, date: DateInRegion().date-580.minutes, length: 20*60, calorie: 200, mileage: 300, steps: 500)
//        
////        trainArray = [t1, t2, t3]
//        trainArray.insert(contentsOf: [t6, t5, t4, t1, t2, t3,], at: 0)
        dateLabel.text = date.dateAt(.startOfDay).toString(.custom("HH:mm"))
        updateChartView()
    }
    
    @IBAction func share(_ sender: Any) {
        let shareView = ShareView(view.captureImage)
        shareView.show()
    }
    //MARK: RangeSliderDelegate
    func sliderDidChanged(index: Int) {
        barChartView.highlightValues([Highlight(x: points[index].point, y: 0, dataSetIndex: 0)])
        updateData(index)
    }
    
    //MARK: ChartViewDelegate
    func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
//        if trainArray.count == 1 {
//            barChartView.highlightValues([Highlight(x: entry.x, y: 0, dataSetIndex: 0)])
//        } else {
        sliderView.didSelectedValue(entry.x)
//        }
    }
    
    private func resetLabel() {
        dateLabel.text = "--"
        trainLabel.text = "--"
    }
    
    private func updateData(_ index: Int) {
        if trainArray.count == 0 {
            resetLabel()
            return
        }
        
        dateLabel.text = points[index].date.toString(.custom("HH:mm"))
        trainLabel.text = LocString(points[index].typeStr)

    }
    
    private func updateChartView() {
        let xAxis = barChartView.xAxis
        xAxis.valueFormatter = IndexAxisValueFormatter(values: DayXValues)
        xAxis.labelCount = 9
        xAxis.axisMinimum = -2.9
        xAxis.axisMaximum = 24 + 2
        
        var chartDataSets = [BarChartDataSet]()
        var emptyEntries = [BarChartDataEntry]()
        for train in trainArray {
            let startX = Double(train.date!.hour) + Double(train.date!.minute)/60.0
            var dataEntries = [BarChartDataEntry]()
            for n in 0..<train.length/60 {
                let pointX = startX+Double(n)*barWidth
                dataEntries.append(BarChartDataEntry(x: pointX, y: max(Double(train.calorie)/1000, barChartView.leftAxis.axisMaximum/10)))
                points.append(TrainPoint(point: pointX, type: train.type!, length: train.length/60, date: train.date!+n.minutes, typeStr: train.typeString!))
                emptyEntries.append(BarChartDataEntry(x: pointX, y: Double(trainArray.max(\.calorie)!.calorie)*1.1/1000))
                if (train.date!+n.minutes).day != train.date!.day {
                    break
                }
            }
            let dateSet = BarChartDataSet(entries: dataEntries)
            dateSet.colors = [UIColor.rgbColorFromHex(0x0CD09B)]
            dateSet.drawValuesEnabled = false
            dateSet.highlightEnabled = false
            chartDataSets.append(dateSet)
        }
        
        
        let highlightSet = BarChartDataSet(entries: emptyEntries)
        highlightSet.colors = [.white]
        highlightSet.highlightEnabled = true
        highlightSet.drawValuesEnabled = false
        highlightSet.highlightColor = UIColor.rgbColorFromHex(0x0CD09B)
        chartDataSets.insert(highlightSet, at: 0)
//        chartDataSets.append(highlightSet)
        let chartData = BarChartData(dataSets: chartDataSets)
        chartData.barWidth = barWidth*2
        barChartView.data = chartData
        
        barChartView.highlightValues([Highlight(x: 0, y: 0, dataSetIndex: 0)])
        setupSliderViewScale()
        
    }
    
    private func setupSliderViewScale() {
        let pointArray = (0..<points.count).map { (i) -> Double in
            return points[i].point
        }
        sliderView.setDrawSpace(startPointX: getChartViewX(0), endPointX: getChartViewX(24), range: 0...24, points: pointArray, imageName: "slider_train")
        
    }
    
    
    
    private func getChartViewX(_ x: Int) -> CGFloat {
        return barChartView.pixelForValues(x: Double(x), y: 0, axis: .left).x
    }
    
    
    private func setupChartView() {
        barChartView.delegate = self
        barChartView.chartDescription?.enabled = false //图描述
        barChartView.legend.enabled = false //左下角图例
        barChartView.setScaleEnabled(false) //可滑动
        barChartView.rightAxis.enabled = false //不绘制右边轴的信息
        
        let leftAxis = barChartView.leftAxis
        leftAxis.labelTextColor = ChartsTextColor
        leftAxis.labelFont = ChartsTextFont(11)
        leftAxis.drawLabelsEnabled = false
        leftAxis.xOffset = -3
        leftAxis.gridLineDashLengths = [2.0, 2.0]  //设置虚线样式的网格线
        leftAxis.gridColor = LineColor
        leftAxis.gridLineWidth = 1
        leftAxis.axisLineWidth = 0
        leftAxis.drawGridLinesBehindDataEnabled = false
        leftAxis.labelPosition = .insideChart
        
        
        leftAxis.axisMinimum = 0 //设置左侧Y轴最小值
        
//        leftAxis.granularity = 1
        
        let litmitLine = ChartLimitLine(limit: 0, label: "")
        litmitLine.lineWidth = 1
        litmitLine.lineColor = LineColor
        leftAxis.addLimitLine(litmitLine)
        leftAxis.drawLimitLinesBehindDataEnabled = false  //设置限制线绘制在折线图的后面
        
        
        let xAxis = barChartView.xAxis
        xAxis.granularity = 1 //间隔
        xAxis.labelPosition = .bottom
        xAxis.labelFont = ChartsTextFont(11)
        xAxis.labelTextColor = ChartsTextColor
        xAxis.drawGridLinesBehindDataEnabled = false
        xAxis.axisLineColor = LineColor
        xAxis.axisLineWidth = 1
        xAxis.gridLineDashLengths = [6, 666]
        xAxis.gridColor = LineColor
        xAxis.drawAxisLineEnabled = false
        
    }
    
    
    @IBAction func back(_ sender: Any) {
        navigationController?.popViewController(animated: true)
    }
    

    
}


extension TrainViewController: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 60
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return trainArray.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let identifier: String = "SubTrainCell\(indexPath.row)\(indexPath.section)"
        if identifierDic[identifier] == nil {
            tableView.register(UINib.init(nibName: "SubTrainCell", bundle: Bundle.main), forCellReuseIdentifier: identifier)
//            tableView.register(UINib(nibName: "SubTrainCell", bundle: .main), forCellWithReuseIdentifier: identifier)
            identifierDic[identifier] = identifier
        }
        let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath) as! SubTrainCell
        
//        let cell = tableView.dequeueReusableCell(withIdentifier: "SubTrainCell", for: indexPath) as! SubTrainCell
        cell.train = trainArray[indexPath.row]
        return cell
    }
}