HeartRateVC.swift 13.2 KB
//
//  HeartRateVC.swift
//  Twear
//
//  Created by yangbin on 2021/11/25.
//

import UIKit
import Charts
import SwiftDate
import MBProgressHUD

class HeartRateVC: UIViewController, DateSegmentViewDelegate, RangeSliderDelegate, ChartViewDelegate, BluetoothSyncDelegate {
    
    @IBOutlet weak var dateSegmentView: DateSegmentView!
    @IBOutlet weak var lineChartView: LineChartView!
    @IBOutlet weak var sliderView: RangeSliderView!
    @IBOutlet weak var dateLabel: UILabel!
    @IBOutlet weak var hrLabel: UILabel!
    @IBOutlet weak var averageLabel: UILabel!
    @IBOutlet weak var quietAverageLabel: UILabel!
    @IBOutlet weak var highLabel: UILabel!
    @IBOutlet weak var lowLabel: UILabel!
    
    private var dateType: DateType = .day
    private var selectedDate = Date()
    private lazy var monthDays = DateInRegion().monthDays
    private var minArray: [Int] = []
    private var maxArray: [Int] = []
    private var points: [Double] = []
    
    private var hrArray: [HeartRateModel] = [] {
        didSet {
            if hrArray.count == 0 {
                resetLabel()
            }
            points = []
            let hr = hrArray.max{$0.value < $1.value}
            let maxHr = max(hr?.value ?? 130, 130)
            lineChartView.leftAxis.axisMaximum = Double(maxHr) * 1.1
        }
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.navigationController?.setNavigationBarHidden(true, animated: true)
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        BluetoothManager.shared.unRegisterSyncDelegate(self)
        MBProgressHUD.hide()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        dateSegmentView.selectedColor = UIColor.rgbColorFromHex(0xD90009)
        dateSegmentView.delegate = self
        sliderView.delegate = self
        BluetoothManager.shared.registerSyncDelegate(self)
        
        //        view.setNeedsLayout()
        view.layoutIfNeeded()
        setupChartView()
        didSelectedDate(date: DateInRegion(), dateType: .day)
    }
    
    func didReceiveHeartRate(value: Int) {
        didSelectedDate(date: DateInRegion(selectedDate), dateType: dateType)
    }
    @IBAction func share(_ sender: Any) {
        let shareView = ShareView(view.captureImage)
        shareView.show()
    }
    //MARK: DateSegmentViewDelegate
    func didSelectedDate(date: DateInRegion, dateType: DateType) {
        self.dateType = dateType
        monthDays = date.monthDays
        selectedDate = date.date
        minArray = []
        maxArray = []
        
        var hrResult: (hrArray: [HeartRateModel], minHr: [Int], maxHr: [Int]) = ([], minArray, maxArray)
        _ = MBProgressHUD.showMessage("")
        DispatchQueue(label: "QueryHeartRate").async {
            switch dateType {
            case .day:
                hrResult = HeartRateModel.getHeartRateByDay(date.date)
            case .week:
                hrResult = HeartRateModel.getHeartRateByWeek(date.date)
            case .month:
                hrResult = HeartRateModel.getHeartRateByMonth(date.date)
            case .year:
                hrResult = HeartRateModel.getHeartRateByYear(date.date)
            }

            DispatchQueue.main.async {
                MBProgressHUD.hide()
                self.minArray = hrResult.minHr
                self.maxArray = hrResult.maxHr
                self.hrArray = hrResult.hrArray
                if self.selectedDate.day == date.date.day && self.selectedDate.month == date.date.month {
                    self.updateChartView()
                } else {
                    print("不能用")
                }
            }
        }
    }
    
    //MARK: RangeSliderDelegate
    func sliderDidChanged(index: Int) {
        lineChartView.highlightValues([Highlight(x: points[index], y: 0, dataSetIndex: 0)])
        updateLable(index)
    }
    
    //MARK: ChartViewDelegate
    func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
        if hrArray.count == 1 {
            lineChartView.highlightValues([Highlight(x: points[0], y: 0, dataSetIndex: 0)])
        } else {
            sliderView.didSelectedValue(entry.x)
        }
    }
    
    private func resetLabel() {
        hrLabel.text = "--"
        averageLabel.text = "--"
        highLabel.text = "--"
        lowLabel.text = "--"
        quietAverageLabel.text = "--"
    }
    
    private func updateLable(_ index: Int) {
        if hrArray.count == 0 {
            resetLabel()
            return
        }
        //        if hrArray[index].value < 0 {
        //            resetLabel()
        //        } else {
        
        if dateType == .day {
            DispatchQueue(label: "QueryHeartRateAverage").async {
                let hrResult = HeartRateModel.getAverageByDay(self.selectedDate)
                DispatchQueue.main.async {
                    self.averageLabel.text = hrResult.hr.value == -1 ? "--" : "\(hrResult.hr.value)"
                    self.highLabel.text = "\(hrResult.maxHr)"
                    self.lowLabel.text = "\(hrResult.minHr)"
                    self.quietAverageLabel.text = "--"
                }
            }
        } else {
            averageLabel.text = hrArray[index].value == -1 ? "--" : "\(hrArray[index].value)"
            self.highLabel.text = "\(maxArray[index])"
            self.lowLabel.text = "\(minArray[index])"
            self.quietAverageLabel.text = "--"
        }

        hrLabel.text = "\(hrArray[index].value)"
        //        }
        let sDate = hrArray[index].date!
        switch dateType {
        case .day:
            dateLabel.text = sDate.toString(.custom("HH:mm"))
        case .week:
            dateLabel.text = sDate.toString(.custom("yyyy.MM.dd")) + " " + sDate.weekText
        case .month:
            dateLabel.text = sDate.toString(.custom("yyyy.MM.dd"))
        case .year:
            dateLabel.text = sDate.toString(.custom("yyyy.MM"))
        }
        if minArray.count > 0 {
            //        if minArray[index] == -1 || maxArray[index] == -1 {
            //            rangeLabel.text = "--"
            //        } else {
            
        } else {
            print("error")
        }
        //        } else {
        //            rangeLabel.text = "--"
        //        }
        
        
        var per = "0"
        switch hrArray[index].value {
        case 0..<10:
            per = "\(hrArray[index].value*2)"
        case 10..<50:
            per = "\(20 + hrArray[index].value)"
        case 50..<70:
            per = "\(60 + (hrArray[index].value-50)/2)"
        case 70..<90:
            per = "\(hrArray[index].value)"
        case 90..<100:
            per = "\(90 + (hrArray[index].value-90)/2)"
        case 100..<120:
            per = String(format:"%.1f",95+Float(hrArray[index].value-100)/5)
        case 120..<300:
            per = "99.9"
        default:
            break
        }
    }
    
    
    private func updateChartView() {
        switch dateType {
        case .day:
            dateLabel.text = selectedDate.dateAt(.startOfDay).toString(.custom("HH:mm"))
        case .week:
            dateLabel.text = (selectedDate.dateAt(.startOfWeek)+1.days).toString(.custom("yyyy.MM.dd")) + " " + LocString("周一")
        case .month:
            dateLabel.text = selectedDate.dateAt(.startOfMonth).toString(.custom("yyyy.MM.dd"))
        case .year:
            dateLabel.text = selectedDate.dateAtStartOf(.year).toString(.custom("yyyy.MM"))
        }
        
        let xAxis = lineChartView.xAxis
        switch dateType {
        case .day:
            xAxis.valueFormatter = IndexAxisValueFormatter(values: DayXValues)
            xAxis.labelCount = 9
            xAxis.axisMinimum = -2.9
            xAxis.axisMaximum = 24 + 2
        case .week:
            xAxis.valueFormatter = IndexAxisValueFormatter(values: WeekXValues)
            xAxis.labelCount = 7
            xAxis.axisMinimum = -0.8
            xAxis.axisMaximum = 6 + 0.8
        case .month:
            xAxis.valueFormatter = IndexAxisValueFormatter(values: MonthXValues(monthDays))
            xAxis.labelCount = 8
            xAxis.axisMinimum = -3.5
            xAxis.axisMinLabels = 8
            xAxis.axisMaximum = Double(monthDays-1) + 2.1
        case .year:
            xAxis.valueFormatter = IndexAxisValueFormatter(values: MonthValues)
            xAxis.labelCount = 12
            xAxis.axisMinimum = -1.3
            xAxis.axisMaximum = 11 + 0.8
        }
        
        var dataEntries = [ChartDataEntry]()
        
        
        
        for hr in hrArray {
            if hr.value > 0 {
                var pointX: Double = 0
                switch dateType {
                case .day:
                    pointX = Double(hr.date!.hour)+Double(hr.date!.minute)/60.0
                case .week:
                    pointX = Double(hr.date!.weekIndex)
                case .month:
                    pointX = Double(hr.date!.day-1)
                case .year:
                    pointX = Double(hr.date!.month-1)
                }
                points.append(pointX)
                dataEntries.append(ChartDataEntry(x: pointX, y: Double(hr.value)))
            }
        }
        
        
        if dataEntries.count == 1 {
            dataEntries.append(ChartDataEntry(x: dataEntries[0].x+0.2, y: dataEntries[0].y))
        }
        
        let dataSet = LineChartDataSet(entries: dataEntries)
        dataSet.drawCirclesEnabled = false
        dataSet.drawValuesEnabled = false
        dataSet.highlightEnabled = true//选中拐点,是否开启高亮效果(显示十字线)
        dataSet.highlightLineWidth = 1
        dataSet.highlightColor = UIColor.rgbColorFromHex(0xD90009)// 十字线颜色
        dataSet.drawHorizontalHighlightIndicatorEnabled = false
        dataSet.mode = .horizontalBezier
        dataSet.setColor(UIColor.rgbColorFromHex(0xD90009))
        dataSet.lineWidth = 1
        
        
        dataSet.drawFilledEnabled = true //填充绘制
        let gradientColors = [UIColor.rgbColorFromHex(0xD90009).cgColor, UIColor.rgbColorFromHex(0xFFFFFF).cgColor]
        let gradient = CGGradient(colorsSpace: nil, colors: gradientColors as CFArray, locations: [1.0, 0.0])
        dataSet.fillAlpha = 1
        dataSet.fill = Fill(linearGradient: gradient!, angle: 90)
        lineChartView.data = LineChartData(dataSets: [dataSet])
        lineChartView.highlightValues([Highlight(x: 0, y: 0, dataSetIndex: 0)])
        
        
        setupSliderViewScale()
    }
    
    
    
    private func setupSliderViewScale() {
        var endPointX: Int = 0
        switch dateType {
        case .day:
            endPointX = 24
        case .week:
            endPointX = 6
        case .month:
            endPointX = monthDays-1
        case .year:
            endPointX = 11
        }
        sliderView.setDrawSpace(startPointX: getChartViewX(0), endPointX: getChartViewX(endPointX), range: 0...endPointX, points: points, imageName: "slider_hr", isLast: true)
    }
    
    private func getChartViewX(_ x: Int) -> CGFloat {
        return lineChartView.pixelForValues(x: Double(x), y: 0, axis: .left).x
    }
    
    private func setupChartView() {
        lineChartView.delegate = self
        lineChartView.noDataText = ""
        lineChartView.chartDescription?.enabled = false //图描述
        lineChartView.legend.enabled = false //左下角图例
        lineChartView.setScaleEnabled(false) //可滑动
        lineChartView.rightAxis.enabled = false //不绘制右边轴的信息
        
        let leftAxis = lineChartView.leftAxis
        leftAxis.labelTextColor = ChartsTextColor
        leftAxis.labelFont = ChartsTextFont(11)
        leftAxis.yOffset = -5
        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.axisMaximum = 130
        leftAxis.granularity = 40
        
        let litmitLine = ChartLimitLine(limit: 0, label: "")
        litmitLine.lineWidth = 1
        litmitLine.lineColor = LineColor
        leftAxis.addLimitLine(litmitLine)
        leftAxis.drawLimitLinesBehindDataEnabled = false  //设置限制线绘制在折线图的后面
        
        
        let xAxis = lineChartView.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 gotoReferenceVC(_ sender: Any) {
        let vc = UIStoryboard.loadViewControllerIdentifier(storyboardName: "Home", identifier: "HRReferenceVC")
        navigationController?.pushViewController(vc, animated: true)
    }
    
    @IBAction func back(_ sender: Any) {
        navigationController?.popViewController(animated: true)
    }
    
    
}