// // HealthModel.swift // Twear // // Created by yangbin on 2021/11/16. // import UIKit import RealmSwift import SwiftDate //MARK: - 步数 class StepModel: Object { @Persisted var number: Int = 0 @Persisted var calorie: Float = 0 //kcal @Persisted var distance: Float = 0 //km @Persisted var date: Date? = nil @Persisted var percent: Int = 0 convenience init(number: Int, calorie: Float = 0, distance: Float = 0, date: Date) { self.init() self.number = number self.distance = Float(Int(distance*100))/100.0 self.calorie = calorie self.percent = min(number*100/StepsGoal, 100) self.date = date } class func toStepArray(_ bytes: [UInt8]) -> [StepModel] { var stepArray: [StepModel] = [] // 将数组分成5个一组 let groupedArray = stride(from: 0, to: bytes.count, by: 5).map { Array(bytes[$0.. StepModel { // let step = bytesToInt(Array(bytes[0..<4])) // print((Float(step)*(0.400 * 175)/100000)) return StepModel(number: bytesToInt(Array(bytes[0..<4])), calorie: bytesToFloat(Array(bytes[4..<8])), distance: bytesToFloat(Array(bytes[8..<12])), date: DateInRegion().date) } private class func stepToCalorie(_ step: Int) -> Float { let user = UserInfo var weight = user.weight if user.weight < 15 { weight = 65 } if user.gender == 1 { return Float((weight - 10)) * stepToDistance(step) } else { return Float((weight - 10)) * stepToDistance(step) * 1.3 } } private class func stepToDistance(_ step: Int) -> Float { let user = UserInfo if user.gender == 1 { return Float(step) * 0.400 * Float(user.height) / 100000 } else { return Float(step) * 0.350 * Float(user.height) / 100000 } } func realTimeAdd(_ isArrayAdd: Bool = false) { // print(self.date) if let date = self.date, date.isInFuture { return } if !isArrayAdd { // 4-11 wyp手环端变大变小bug处理 if let stepsToday = RealmTools.queryObjects(StepModel.self, filter: "date >= %@ AND date <= %@", [self.date!.dateAtStartOf(.day), self.date!.dateAtStartOf(.day)+1.days-1.seconds]) as? [StepModel], let lastStep = stepsToday.last { if lastStep.number >= self.number { return } } } if let stepArray = RealmTools.queryObjects(StepModel.self, filter: "date >= %@ AND date <= %@", [self.date!.dateAtStartOf(.hour), self.date!.dateAtStartOf(.hour)+1.hours-1.seconds]) as? [StepModel] { RealmTools.deleteList(stepArray) } RealmTools.add(StepModel(number: self.number, calorie: self.calorie, distance: self.distance, date: self.date!.dateAtStartOf(.hour))) } // stepArray.count > 0 { // let model = stepArray.last // RealmTools.updateWithTranstion { (true) in // model?.date = self.date // model?.number = self.number // model?.calorie = self.calorie // model?.distance = self.distance class func addArray(_ array: [StepModel]) { for step in array { // if step.number > 0 { step.realTimeAdd(true) // } } } class func getRecentSteps() -> StepModel { let step = StepModel(number: 0, calorie: 0, distance: 0, date: DateInRegion().date) guard let array = RealmTools.objectsWithPredicateAndSortedForPages(object: self, sortedKey: "date", isAssending: false, pageSize: 1) as? [StepModel], array.count > 0 else { return step } return array.reversed().first ?? step } class func getLastWeekSteps() -> [StepModel] { var stepArray: [StepModel] = [] let date = (DateInRegion().date - 6.days).dateAtStartOf(.day) for i in 0..<7 { let startDate = date + i.days let array = getStepHistory(startTime: startDate, endTime: startDate+1.days-1.seconds) if let step = array.last { stepArray.append(step) } else { stepArray.append(StepModel(number: 0, calorie: 0, distance: 0, date: startDate)) } } return stepArray } class func getStepsByDay(_ date: Date) -> [StepModel] { var stepArray = getStepHistory(startTime: date.dateAtStartOf(.day), endTime: date.dateAtEndOf(.day)) guard let step = stepArray.first, let firstDate = step.date else { return [] } if firstDate.isAfterDate(firstDate.dateAtStartOf(.day)+1.hours, orEqual: true, granularity: .hour) { stepArray.insert(StepModel(number: 0, calorie: 0, distance: 0, date: firstDate.date.dateAtStartOf(.hour)-1.hours), at: 0) } if let lastStep = stepArray.last, (DateInRegion().date.isAfterDate(lastStep.date!, orEqual: false, granularity: .minute) && DateInRegion().date.isInside(date: lastStep.date!, granularity: .day)) { stepArray[stepArray.count-1] = StepModel(number: lastStep.number, calorie: lastStep.calorie, distance: lastStep.distance, date: DateInRegion().date) } return stepArray } class func getStepsByWeek(_ date: Date) -> [StepModel] { var stepArray: [StepModel] = [] let weekDays = date.compare(.isThisWeek) ? (DateInRegion()-1.days).weekday : 7 for i in 0.. [StepModel] { var stepArray: [StepModel] = [] let monthDays = date.compare(.isThisMonth) ? DateInRegion().day : date.monthDays for i in 0.. [StepModel] { // var stepArray: [StepModel] = [] // let yearMonths = date.compare(.isThisYear) ? DateInRegion().month : 12 // for i in 0.. 0 { // bpArray.append(BloodPressureModel(dbp: array.average(\.dbp), sbp: array.average(\.sbp), date: startDate)) // } return stepArray } class func getMaxStepsByYear(_ date: Date) -> (max: StepModel, array: [StepModel]) { var stepArray: [StepModel] = [] var maxStepArray: [StepModel] = [] let yearMonths = date.compare(.isThisYear) ? DateInRegion().month : 12 for i in 0.. [StepModel] { // let p = NSPredicate(format: "date >= %@ AND date <= %@", startTime, endTime) let array = RealmTools.objectsWithPredicateAndSorted(object: self, predicate: NSPredicate(format: "date >= %@ AND date <= %@", argumentArray:[startTime, endTime]), sortedKey: "date") // RealmTools.queryObjects(self, filter: "date >= %@ AND date <= %@", [startTime, endTime]) if array == nil { return [] } else { return array as! [StepModel] } } class func updateStep(date: Date, step: Int) { guard let array = RealmTools.queryObjects(self, filter: "date >= %@ AND date <= %@", [date.dateAtStartOf(.hour).date, date.dateAtEndOf(.hour).date]) as? Array, array.count > 0 else { return } let model = array.last RealmTools.updateWithTranstion { (true) in model?.number = step } } } //MARK: - 心率 class HeartRateModel: Object { @Persisted var value: Int = -1 @Persisted var date: Date? = nil convenience init(value: Int, date: Date?) { self.init() self.value = value self.date = date } class func toHeartRateArray(_ bytes: [UInt8]) -> [HeartRateModel] { var hrArray: [HeartRateModel] = [] // 将数组分成5个一组 let groupedArray = stride(from: 0, to: bytes.count, by: 5).map { Array(bytes[$0.. Bool { if self.value == hr.value { if self.date!.isInside(date: hr.date!, granularity: .minute) { return true } } return false } func realTimeAdd() { if let hrArray = RealmTools.queryObjects(HeartRateModel.self) as? [HeartRateModel], let hr = hrArray.last { if !self.isEqual(hr) { RealmTools.add(self) } } else { RealmTools.add(self) } } class func addArray(_ array: [HeartRateModel]) { if array.count == 0 { return } for (i, hr) in array.enumerated() { if hr == array.first { hr.add() } else { if !hr.isEqual(array[i-1]) { hr.add() } } } } class func getRecentData(count: Int = 31) -> [HeartRateModel] { guard let array = RealmTools.objectsWithPredicateAndSortedForPages(object: self, sortedKey: "date", isAssending: false, pageSize: count) as? [HeartRateModel], array.count > 0 else { return [] } return array.reversed() } class func getHeartRateByDay(_ date: Date) -> (hrArray: [HeartRateModel], minHr: [Int], maxHr: [Int]) { var hrArray: [HeartRateModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] for h in 0..<24 { let hourArray = getHistoryHeartRate(startTime: date.dateAtStartOf(.day)+h.hours, endTime: date.dateAtStartOf(.day)+(h+1).hours) for m in 0..<60 { var minuteArray: [HeartRateModel] = [] for hr in hourArray { if hr.date!.minute == m { minuteArray.append(hr) } } if minuteArray.count > 0 { hrArray.append(HeartRateModel(value: minuteArray.last!.value, date: date.dateAtStartOf(.day)+h.hours+m.minutes)) // hrArray.append(HeartRateModel(value: minuteArray.average(\.value), date: date.dateAtStartOf(.day)+h.hours+m.minutes)) minArray.append(minuteArray.min(\.value)?.value ?? -1) maxArray.append(minuteArray.max(\.value)?.value ?? -1) } } } /* for i in 0..<24 { for m in 0..<60 { rec += 1 let minuteArray = getHistoryHeartRate(startTime: date.dateAtStartOf(.day)+i.hours+m.minutes, endTime: date.dateAtStartOf(.day)+i.hours+(m+1).minutes) if minuteArray.count > 0 { hrArray.append(HeartRateModel(value: minuteArray.average(\.value), date: date.dateAtStartOf(.day)+i.hours+m.minutes)) minArray.append(minuteArray.min(\.value)?.value ?? -1) maxArray.append(minuteArray.max(\.value)?.value ?? -1) } } } */ // if hrArray.count > 1 { // minArray.insert(hrArray[0].value, at: 0) // maxArray.insert(hrArray[0].value, at: 0) // } return (hrArray, minArray, maxArray) } class func getAverageByDay(_ date: Date) -> (hr: HeartRateModel, minHr: Int, maxHr: Int) { let startDate = date.dateAt(.startOfDay) let array = getHistoryHeartRate(startTime: startDate, endTime: startDate+1.days-1.seconds) return (HeartRateModel(value: array.average(\.value), date: startDate), array.min(\.value)?.value ?? -1, array.max(\.value)?.value ?? -1) // return BloodPressureModel(dbp: array.average(\.dbp), sbp: array.average(\.sbp), date: startDate) } class func getHeartRateByWeek(_ date: Date) -> (hrArray: [HeartRateModel], minHr: [Int], maxHr: [Int]) { var hrArray: [HeartRateModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] let weekDays = date.compare(.isThisWeek) ? (DateInRegion()-1.days).weekday : 7 for i in 0.. 0 { hrArray.append(HeartRateModel(value: array.average(\.value), date: startDate)) minArray.append(array.min(\.value)?.value ?? -1) maxArray.append(array.max(\.value)?.value ?? -1) } } return (hrArray, minArray, maxArray) } class func getHeartRateByMonth(_ date: Date) -> (hrArray: [HeartRateModel], minHr: [Int], maxHr: [Int]) { var hrArray: [HeartRateModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] let monthDays = date.compare(.isThisMonth) ? DateInRegion().day : date.monthDays for i in 0.. 0 { hrArray.append(HeartRateModel(value: array.average(\.value), date: startDate)) minArray.append(array.min(\.value)?.value ?? -1) maxArray.append(array.max(\.value)?.value ?? -1) } } return (hrArray, minArray, maxArray) } class func getHeartRateByYear(_ date: Date) -> (hrArray: [HeartRateModel], minHr: [Int], maxHr: [Int]) { var hrArray: [HeartRateModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] let yearMonths = date.compare(.isThisYear) ? DateInRegion().month : 12 for i in 0.. 0 { hrArray.append(HeartRateModel(value: array.average(\.value), date: startDate)) minArray.append(array.min(\.value)?.value ?? -1) maxArray.append(array.max(\.value)?.value ?? -1) } } return (hrArray, minArray, maxArray) } private class func getHistoryHeartRate(startTime: Date, endTime: Date) -> [HeartRateModel] { guard let array = RealmTools.objectsWithPredicateAndSorted(object: self, predicate: NSPredicate(format: "date >= %@ AND date <= %@", argumentArray:[startTime, endTime]), sortedKey: "date") as? Array, array.count > 0 else { return [] } return array } } //MARK: - 体温 class TemperatureModel: Object { @Persisted var value: Int = -1 @Persisted var date: Date? = nil convenience init(value: Int, date: Date?) { self.init() self.value = value self.date = date } class func toTemperatureArray(_ bytes: [UInt8]) -> [TemperatureModel] { var tArray: [TemperatureModel] = [] // 将数组分成5个一组 let groupedArray = stride(from: 0, to: bytes.count, by: 5).map { Array(bytes[$0.. Bool { if self.value == hr.value { if self.date!.isInside(date: hr.date!, granularity: .minute) { return true } } return false } func realTimeAdd() { if let hrArray = RealmTools.queryObjects(TemperatureModel.self) as? [TemperatureModel], let hr = hrArray.last { if !self.isEqual(hr) { RealmTools.add(self) } } else { RealmTools.add(self) } } class func addArray(_ array: [TemperatureModel]) { if array.count == 0 { return } for (i, hr) in array.enumerated() { if hr == array.first { hr.add() } else { if !hr.isEqual(array[i-1]) { hr.add() } } } } class func getRecentData(count: Int = 31) -> [TemperatureModel] { guard let array = RealmTools.objectsWithPredicateAndSortedForPages(object: self, sortedKey: "date", isAssending: false, pageSize: count) as? [TemperatureModel], array.count > 0 else { return [] } return array.reversed() } class func getTemperatureByDay(_ date: Date) -> (hrArray: [TemperatureModel], minHr: [Int], maxHr: [Int]) { var hrArray: [TemperatureModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] for h in 0..<24 { let hourArray = getHistoryTemperature(startTime: date.dateAtStartOf(.day)+h.hours, endTime: date.dateAtStartOf(.day)+(h+1).hours) for m in 0..<60 { var minuteArray: [TemperatureModel] = [] for hr in hourArray { if hr.date!.minute == m { minuteArray.append(hr) } } if minuteArray.count > 0 { hrArray.append(TemperatureModel(value: minuteArray.last!.value, date: date.dateAtStartOf(.day)+h.hours+m.minutes)) // hrArray.append(HeartRateModel(value: minuteArray.average(\.value), date: date.dateAtStartOf(.day)+h.hours+m.minutes)) minArray.append(minuteArray.min(\.value)?.value ?? -1) maxArray.append(minuteArray.max(\.value)?.value ?? -1) } } } /* for i in 0..<24 { for m in 0..<60 { rec += 1 let minuteArray = getHistoryHeartRate(startTime: date.dateAtStartOf(.day)+i.hours+m.minutes, endTime: date.dateAtStartOf(.day)+i.hours+(m+1).minutes) if minuteArray.count > 0 { hrArray.append(HeartRateModel(value: minuteArray.average(\.value), date: date.dateAtStartOf(.day)+i.hours+m.minutes)) minArray.append(minuteArray.min(\.value)?.value ?? -1) maxArray.append(minuteArray.max(\.value)?.value ?? -1) } } } */ // if hrArray.count > 1 { // minArray.insert(hrArray[0].value, at: 0) // maxArray.insert(hrArray[0].value, at: 0) // } return (hrArray, minArray, maxArray) } class func getAverageByDay(_ date: Date) -> (hr: TemperatureModel, minHr: Int, maxHr: Int) { let startDate = date.dateAt(.startOfDay) let array = getHistoryTemperature(startTime: startDate, endTime: startDate+1.days-1.seconds) return (TemperatureModel(value: array.average(\.value), date: startDate), array.min(\.value)?.value ?? -1, array.max(\.value)?.value ?? -1) // return BloodPressureModel(dbp: array.average(\.dbp), sbp: array.average(\.sbp), date: startDate) } class func getTemperatureByWeek(_ date: Date) -> (hrArray: [TemperatureModel], minHr: [Int], maxHr: [Int]) { var hrArray: [TemperatureModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] let weekDays = date.compare(.isThisWeek) ? (DateInRegion()-1.days).weekday : 7 for i in 0.. 0 { hrArray.append(TemperatureModel(value: array.average(\.value), date: startDate)) minArray.append(array.min(\.value)?.value ?? -1) maxArray.append(array.max(\.value)?.value ?? -1) } } return (hrArray, minArray, maxArray) } class func getTemperatureByMonth(_ date: Date) -> (hrArray: [TemperatureModel], minHr: [Int], maxHr: [Int]) { var hrArray: [TemperatureModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] let monthDays = date.compare(.isThisMonth) ? DateInRegion().day : date.monthDays for i in 0.. 0 { hrArray.append(TemperatureModel(value: array.average(\.value), date: startDate)) minArray.append(array.min(\.value)?.value ?? -1) maxArray.append(array.max(\.value)?.value ?? -1) } } return (hrArray, minArray, maxArray) } class func getTemperatureByYear(_ date: Date) -> (hrArray: [TemperatureModel], minHr: [Int], maxHr: [Int]) { var hrArray: [TemperatureModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] let yearMonths = date.compare(.isThisYear) ? DateInRegion().month : 12 for i in 0.. 0 { hrArray.append(TemperatureModel(value: array.average(\.value), date: startDate)) minArray.append(array.min(\.value)?.value ?? -1) maxArray.append(array.max(\.value)?.value ?? -1) } } return (hrArray, minArray, maxArray) } private class func getHistoryTemperature(startTime: Date, endTime: Date) -> [TemperatureModel] { guard let array = RealmTools.objectsWithPredicateAndSorted(object: self, predicate: NSPredicate(format: "date >= %@ AND date <= %@", argumentArray:[startTime, endTime]), sortedKey: "date") as? Array, array.count > 0 else { return [] } return array } } //MARK: - 压力 //jtd! class StressModel: Object { @Persisted var value: Int = -1 @Persisted var date: Date? = nil convenience init(value: Int, date: Date?) { self.init() self.value = value self.date = date } class func toStressArray(_ bytes: [UInt8]) -> [StressModel] { var hrArray: [StressModel] = [] let num = bytes.count/7 for i in 0.. Bool { if self.value == hr.value { if self.date!.isInside(date: hr.date!, granularity: .minute) { return true } } return false } func realTimeAdd() { if let hrArray = RealmTools.queryObjects(StressModel.self) as? [StressModel], let hr = hrArray.last { if !self.isEqual(hr) { RealmTools.add(self) } } else { RealmTools.add(self) } } class func addArray(_ array: [StressModel]) { if array.count == 0 { return } for (i, hr) in array.enumerated() { if hr == array.first { hr.add() } else { if !hr.isEqual(array[i-1]) { hr.add() } } } } class func getRecentData(count: Int = 31) -> [StressModel] { guard let array = RealmTools.objectsWithPredicateAndSortedForPages(object: self, sortedKey: "date", isAssending: false, pageSize: count) as? [StressModel], array.count > 0 else { return [] } return array.reversed() } class func getStressByDay(_ date: Date) -> (hrArray: [StressModel], minHr: [Int], maxHr: [Int]) { var hrArray: [StressModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] for h in 0..<24 { let hourArray = getHistoryStress(startTime: date.dateAtStartOf(.day)+h.hours, endTime: date.dateAtStartOf(.day)+(h+1).hours) for m in 0..<60 { var minuteArray: [StressModel] = [] for hr in hourArray { if hr.date!.minute == m { minuteArray.append(hr) } } if minuteArray.count > 0 { hrArray.append(StressModel(value: minuteArray.last!.value, date: date.dateAtStartOf(.day)+h.hours+m.minutes)) // hrArray.append(HeartRateModel(value: minuteArray.average(\.value), date: date.dateAtStartOf(.day)+h.hours+m.minutes)) minArray.append(minuteArray.min(\.value)?.value ?? -1) maxArray.append(minuteArray.max(\.value)?.value ?? -1) } } } /* for i in 0..<24 { for m in 0..<60 { rec += 1 let minuteArray = getHistoryHeartRate(startTime: date.dateAtStartOf(.day)+i.hours+m.minutes, endTime: date.dateAtStartOf(.day)+i.hours+(m+1).minutes) if minuteArray.count > 0 { hrArray.append(HeartRateModel(value: minuteArray.average(\.value), date: date.dateAtStartOf(.day)+i.hours+m.minutes)) minArray.append(minuteArray.min(\.value)?.value ?? -1) maxArray.append(minuteArray.max(\.value)?.value ?? -1) } } } */ // if hrArray.count > 1 { // minArray.insert(hrArray[0].value, at: 0) // maxArray.insert(hrArray[0].value, at: 0) // } return (hrArray, minArray, maxArray) } class func getAverageByDay(_ date: Date) -> (hr: StressModel, minHr: Int, maxHr: Int) { let startDate = date.dateAt(.startOfDay) let array = getHistoryStress(startTime: startDate, endTime: startDate+1.days-1.seconds) return (StressModel(value: array.average(\.value), date: startDate), array.min(\.value)?.value ?? -1, array.max(\.value)?.value ?? -1) // return BloodPressureModel(dbp: array.average(\.dbp), sbp: array.average(\.sbp), date: startDate) } class func getStressByWeek(_ date: Date) -> (hrArray: [StressModel], minHr: [Int], maxHr: [Int]) { var hrArray: [StressModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] let weekDays = date.compare(.isThisWeek) ? (DateInRegion()-1.days).weekday : 7 for i in 0.. 0 { hrArray.append(StressModel(value: array.average(\.value), date: startDate)) minArray.append(array.min(\.value)?.value ?? -1) maxArray.append(array.max(\.value)?.value ?? -1) } } return (hrArray, minArray, maxArray) } class func getStressByMonth(_ date: Date) -> (hrArray: [StressModel], minHr: [Int], maxHr: [Int]) { var hrArray: [StressModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] let monthDays = date.compare(.isThisMonth) ? DateInRegion().day : date.monthDays for i in 0.. 0 { hrArray.append(StressModel(value: array.average(\.value), date: startDate)) minArray.append(array.min(\.value)?.value ?? -1) maxArray.append(array.max(\.value)?.value ?? -1) } } return (hrArray, minArray, maxArray) } class func getStressByYear(_ date: Date) -> (hrArray: [StressModel], minHr: [Int], maxHr: [Int]) { var hrArray: [StressModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] let yearMonths = date.compare(.isThisYear) ? DateInRegion().month : 12 for i in 0.. 0 { hrArray.append(StressModel(value: array.average(\.value), date: startDate)) minArray.append(array.min(\.value)?.value ?? -1) maxArray.append(array.max(\.value)?.value ?? -1) } } return (hrArray, minArray, maxArray) } private class func getHistoryStress(startTime: Date, endTime: Date) -> [StressModel] { guard let array = RealmTools.objectsWithPredicateAndSorted(object: self, predicate: NSPredicate(format: "date >= %@ AND date <= %@", argumentArray:[startTime, endTime]), sortedKey: "date") as? Array, array.count > 0 else { return [] } return array } } //MARK: - 血压 class BloodPressureModel: Object { @Persisted var sbp: Int = -1 @Persisted var dbp: Int = -1 @Persisted var date: Date? = nil convenience init(dbp: Int, sbp: Int, date: Date?) { self.init() self.sbp = sbp self.dbp = dbp self.date = date } class func toBloodPressureArray(_ bytes: [UInt8]) -> [BloodPressureModel] { var bpArray: [BloodPressureModel] = [] let num = bytes.count/8 for i in 0.. Bool { if self.sbp == bp.sbp && self.dbp == bp.dbp { if self.date!.isInside(date: bp.date!, granularity: .minute) { return true } } return false } func realTimeAdd() { if let bpArray = RealmTools.queryObjects(BloodPressureModel.self) as? [BloodPressureModel], let bp = bpArray.last { if !self.isEqual(bp) { RealmTools.add(self) } } else { RealmTools.add(self) } } class func addArray(_ array: [BloodPressureModel]) { if array.count == 0 { return } for (i, bp) in array.enumerated() { if bp == array.first { bp.add() } else { if !bp.isEqual(array[i-1]) { bp.add() } } } } class func getRecentData(count: Int = 31) -> [BloodPressureModel] { guard let array = RealmTools.objectsWithPredicateAndSortedForPages(object: self, sortedKey: "date", isAssending: false, pageSize: count) as? [BloodPressureModel], array.count > 0 else { return [] } return array.reversed() } class func getBloodPressureByDay(_ date: Date) -> [BloodPressureModel] { var bpArray: [BloodPressureModel] = [] for h in 0..<24 { let hourArray = getHistoryBloodPressure(startTime: date.dateAtStartOf(.day)+h.hours, endTime: date.dateAtStartOf(.day)+(h+1).hours-1.seconds) for m in 0..<60 { var minuteArray: [BloodPressureModel] = [] for bp in hourArray { if bp.date!.minute == m { minuteArray.append(bp) } } if minuteArray.count > 0 { bpArray.append(BloodPressureModel(dbp: minuteArray.last!.dbp, sbp: minuteArray.last!.sbp, date: date.dateAtStartOf(.day)+h.hours+m.minutes)) // bpArray.append(BloodPressureModel(dbp: minuteArray.average(\.dbp), sbp: minuteArray.average(\.sbp), date: date.dateAtStartOf(.day)+h.hours+m.minutes)) } } } return bpArray } class func getAverageByDay(_ date: Date) -> BloodPressureModel { let startDate = date.dateAt(.startOfDay) let array = getHistoryBloodPressure(startTime: startDate, endTime: startDate+1.days-1.seconds) return BloodPressureModel(dbp: array.average(\.dbp), sbp: array.average(\.sbp), date: startDate) } class func getBloodPressureByWeek(_ date: Date) -> [BloodPressureModel] { var bpArray: [BloodPressureModel] = [] let weekDays = date.compare(.isThisWeek) ? (DateInRegion()-1.days).weekday : 7 print(date.compare(.isThisWeek)) for i in 0.. 0 { bpArray.append(BloodPressureModel(dbp: array.average(\.dbp), sbp: array.average(\.sbp), date: startDate)) } } return bpArray } class func getBloodPressureByMonth(_ date: Date) -> [BloodPressureModel] { var bpArray: [BloodPressureModel] = [] let monthDays = date.compare(.isThisMonth) ? DateInRegion().day : date.monthDays for i in 0.. 0 { bpArray.append(BloodPressureModel(dbp: array.average(\.dbp), sbp: array.average(\.sbp), date: startDate)) } } return bpArray } class func getBloodPressureByYear(_ date: Date) -> [BloodPressureModel] { var bpArray: [BloodPressureModel] = [] let yearMonths = date.compare(.isThisYear) ? DateInRegion().month : 12 for i in 0.. 0 { bpArray.append(BloodPressureModel(dbp: array.average(\.dbp), sbp: array.average(\.sbp), date: startDate)) } } return bpArray } private class func getHistoryBloodPressure(startTime: Date, endTime: Date) -> [BloodPressureModel] { guard let array = RealmTools.objectsWithPredicateAndSorted(object: self, predicate: NSPredicate(format: "date >= %@ AND date <= %@", argumentArray:[startTime, endTime]), sortedKey: "date") as? Array, array.count > 0 else { return [] } return array } } //MARK: - 血氧 class BloodOxygenModel: Object { @Persisted var value: Int = -1 @Persisted var date: Date? = nil convenience init(value: Int, date: Date?) { self.init() self.value = value self.date = date } class func toBloodOxygenArray(_ bytes: [UInt8]) -> [BloodOxygenModel] { var boArray: [BloodOxygenModel] = [] // 将数组分成5个一组 let groupedArray = stride(from: 0, to: bytes.count, by: 5).map { Array(bytes[$0.. Bool { if self.value == bo.value { if self.date!.isInside(date: bo.date!, granularity: .minute) { return true } } return false } func realTimeAdd() { if let boArray = RealmTools.queryObjects(BloodOxygenModel.self) as? [BloodOxygenModel], let bo = boArray.last { if !self.isEqual(bo) { RealmTools.add(self) } } else { print("第一次测量") RealmTools.add(self) } } class func addArray(_ array: [BloodOxygenModel]) { if array.count == 0 { return } for (i, bo) in array.enumerated() { if bo == array.first { bo.add() } else { if !bo.isEqual(array[i-1]) { bo.add() } } } } class func getRecentData(count: Int = 31) -> [BloodOxygenModel] { guard let array = RealmTools.objectsWithPredicateAndSortedForPages(object: self, sortedKey: "date", isAssending: false, pageSize: count) as? [BloodOxygenModel], array.count > 0 else { return [] } return array.reversed() } class func getBloodOxygenByDay(_ date: Date) -> (boArray: [BloodOxygenModel], minBo: [Int], maxBo: [Int]) { var boArray: [BloodOxygenModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] for h in 0..<24 { let hourArray = getHistoryBloodOxygen(startTime: date.dateAtStartOf(.day)+h.hours, endTime: date.dateAtStartOf(.day)+(h+1).hours-1.seconds) for m in 0..<60 { var minuteArray: [BloodOxygenModel] = [] for bo in hourArray { if bo.date!.minute == m { minuteArray.append(bo) } } if minuteArray.count > 0 { boArray.append(BloodOxygenModel(value: minuteArray.last!.value, date: date.dateAtStartOf(.day)+h.hours+m.minutes)) // boArray.append(BloodOxygenModel(value: minuteArray.average(\.value), date: date.dateAtStartOf(.day)+h.hours+m.minutes)) minArray.append(minuteArray.min(\.value)?.value ?? -1) maxArray.append(minuteArray.max(\.value)?.value ?? -1) } } } // if boArray.count > 0 { // minArray.insert(boArray[0].value, at: 0) // maxArray.insert(boArray[0].value, at: 0) // } return (boArray, minArray, maxArray) } class func getAverageByDay(_ date: Date) -> (bo: BloodOxygenModel, minBo: Int, maxBo: Int) { let startDate = date.dateAt(.startOfDay) let array = getHistoryBloodOxygen(startTime: startDate, endTime: startDate+1.days-1.seconds) return (BloodOxygenModel(value: array.average(\.value), date: startDate), array.min(\.value)?.value ?? -1, array.max(\.value)?.value ?? -1) // return BloodPressureModel(dbp: array.average(\.dbp), sbp: array.average(\.sbp), date: startDate) } class func getBloodOxygenByWeek(_ date: Date) -> (boArray: [BloodOxygenModel], minBo: [Int], maxBo: [Int]) { var boArray: [BloodOxygenModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] let weekDays = date.compare(.isThisWeek) ? (DateInRegion()-1.days).weekday : 7 for i in 0.. 0 { boArray.append(BloodOxygenModel(value: array.average(\.value), date: startDate)) minArray.append(array.min(\.value)?.value ?? -1) maxArray.append(array.max(\.value)?.value ?? -1) } } return (boArray, minArray, maxArray) } class func getBloodOxygenByMonth(_ date: Date) -> (boArray: [BloodOxygenModel], minBo: [Int], maxBo: [Int]) { var boArray: [BloodOxygenModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] let monthDays = date.compare(.isThisMonth) ? DateInRegion().day : date.monthDays for i in 0.. 0 { boArray.append(BloodOxygenModel(value: array.average(\.value), date: startDate)) minArray.append(array.min(\.value)?.value ?? -1) maxArray.append(array.max(\.value)?.value ?? -1) } } return (boArray, minArray, maxArray) } class func getBloodOxygenByYear(_ date: Date) -> (boArray: [BloodOxygenModel], minBo: [Int], maxBo: [Int]) { var boArray: [BloodOxygenModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] let yearMonths = date.compare(.isThisYear) ? DateInRegion().month : 12 for i in 0.. 0 { boArray.append(BloodOxygenModel(value: array.average(\.value), date: startDate)) minArray.append(array.min(\.value)?.value ?? -1) maxArray.append(array.max(\.value)?.value ?? -1) } } return (boArray, minArray, maxArray) } private class func getHistoryBloodOxygen(startTime: Date, endTime: Date) -> [BloodOxygenModel] { guard let array = RealmTools.objectsWithPredicateAndSorted(object: self, predicate: NSPredicate(format: "date >= %@ AND date <= %@", argumentArray:[startTime, endTime]), sortedKey: "date") as? Array, array.count > 0 else { return [] } return array } } //MARK: - 睡眠 enum SleepType: Int { case awake = 7 case eyeMove = 8 case light = 9 case deep = 10 } class SleepModel: Object { @Persisted var startDate: Date? = nil @Persisted var endDate: Date? = nil @Persisted private var typeRaw: Int = 0 @Persisted var length: Int = 0 // private var sleepTimeClosure: ((_ error: Int?) -> ())? var type: SleepType? { get { return SleepType(rawValue: typeRaw) } set { typeRaw = newValue?.rawValue ?? 0 } } convenience init(type: SleepType, startDate: Date, endDate: Date) { self.init() self.type = type self.startDate = startDate self.endDate = endDate self.length = (endDate-startDate).in(.minute) ?? 0 } class func toSleepArray(_ bytes: [UInt8]) -> [SleepModel] { var sleepArray: [SleepModel] = [] // 将数组分成13个一组 let groupedArray = stride(from: 0, to: bytes.count, by: 13).map { Array(bytes[$0.. SleepSummary { if array.count > 0 { var awake: Int = 0 var deep: Int = 0 var light: Int = 0 let startDate = array.first?.startDate let endDate = array.last?.endDate for sleep in array { switch sleep.type { case .awake: awake += sleep.length case .deep: deep += sleep.length case .light: light += sleep.length default: break } } return SleepSummary(awake: awake, light: light, deep: deep, startDate: startDate!, endDate: endDate!) } else { return SleepSummary() } } func add() { if let a = RealmTools.queryObjects(SleepModel.self, filter: "startDate = %@ AND endDate = %@", [self.startDate ?? Date(), self.endDate ?? Date()]) as? [SleepModel], a.count > 0 { let model = a.last RealmTools.updateWithTranstion { (true) in // model?.typeRaw = self.typeRaw model?.startDate = self.startDate model?.length = self.length model?.endDate = self.endDate model?.typeRaw = self.typeRaw } // RealmTools.deleteList(a) } else { RealmTools.add(self) } } class func addArray(_ array :[SleepModel]) { if let date = array.last?.endDate { let startDate = date.dateAtStartOf(.day) - 2.hours let endDate = date.dateAtStartOf(.day) + 12.hours if let a = RealmTools.queryObjects(SleepModel.self, filter: "startDate >= %@ AND endDate <= %@", [startDate, endDate]) as? [SleepModel] { RealmTools.deleteList(a) } } for sleep in array { sleep.add() } } class func querySleepTime(_ array: [SleepModel], sleepTime: ((_ awakeTime: Int, _ lightTime: Int, _ deepTime: Int) -> ())) { //-> (awakeTime: Int, lightTime: Int, deepTime: Int) { var awake: Int = 0 var light: Int = 0 var deep: Int = 0 for sleep in array { switch sleep.type { case .awake: awake += sleep.length case .light: light += sleep.length case .deep: deep += sleep.length case .none: break default: break } } sleepTime(awake, light, deep) } class func querySleepPercentage(_ array: [SleepModel]) -> (awake_pct: Int, light_pct: Int, deep_pct: Int, length: Int) { var awake: Int = 0 var light: Int = 0 var deep: Int = 0 for sleep in array { switch sleep.type { case .awake: awake += sleep.length case .light: light += sleep.length case .deep: deep += sleep.length case .none: break default: break } } let length = awake + light + deep let deep_pct = deep*100/length var light_pct = 0 var awake_pct = 0 if awake == 0 { light_pct = 100 - deep_pct } else { light_pct = light*100/length awake_pct = 100 - deep_pct - light_pct } return (awake_pct, light_pct, deep_pct, (deep+light)) } class func getRecentData(count: Int = 31) -> SleepSummary { guard let array = RealmTools.objectsWithPredicateAndSortedForPages(object: self, sortedKey: "startDate", isAssending: false, pageSize: count) as? [SleepModel], array.count > 0 else { return SleepSummary() } let date = array.first!.startDate return toSleepSummary(getSleepByDay(date!)) } class func getSleepByDay(_ date: Date) -> [SleepModel] { return getHistorySleep(startTime: date.dateAtStartOf(.day)-2.hours, endTime: date.dateAtEndOf(.day)-2.hours) } class func getSleepByWeek(_ date: Date) -> [SleepSummary] { var sleepArray: [SleepSummary] = [] let weekDays = date.compare(.isThisWeek) ? (DateInRegion()-1.days).weekday : 7 for i in 0.. 0 { sleepArray.append(toSleepSummary(array)) } } return sleepArray } class func getSleepByMonth(_ date: Date) -> [SleepSummary] { var sleepArray: [SleepSummary] = [] let monthDays = date.compare(.isThisMonth) ? DateInRegion().day : date.monthDays for i in 0.. 0 { sleepArray.append(toSleepSummary(array)) } } return sleepArray } class func getSleepByYear(_ date: Date) -> [SleepSummary] { var sleepArray: [SleepSummary] = [] let yearMonths = date.compare(.isThisYear) ? DateInRegion().month : 12 for i in 0.. 0 { let summary = SleepSummary(awake: array.average(\.awake), light: array.average(\.light), deep: array.average(\.deep), startDate: startDate, endDate: startDate.dateAtEndOf(.month), totalLength: array.sum(\.sleepLength)) sleepArray.append(summary) } } return sleepArray } private class func getHistorySleep(startTime: Date, endTime: Date) -> [SleepModel] { guard let array = RealmTools.objectsWithPredicateAndSorted(object: self, predicate: NSPredicate(format: "startDate >= %@ AND endDate <= %@", argumentArray:[startTime, endTime]), sortedKey: "startDate") as? Array, array.count > 0 else { return [] } // guard let array = RealmTools.queryObjects(self, filter: "startDate >= %@ AND endDate <= %@", [startTime, endTime]) as? Array, array.count > 0 else { // return [] // } return array } } class SleepSummary: NSObject { var startDate: Date? = nil var endDate: Date? = nil var awake: Int = 0 var light: Int = 0 var deep: Int = 0 var sleepLength: Int = 0 var awake_pct: Int = 0 var light_pct: Int = 0 var deep_pct: Int = 0 var totalLength: Int = 0 init(awake: Int, light: Int, deep: Int, startDate: Date, endDate: Date, totalLength: Int = 0) { super.init() self.startDate = startDate self.endDate = endDate self.awake = awake self.deep = deep self.light = light self.sleepLength = deep + light let length = deep + light + awake self.totalLength = totalLength let deep_pct = deep*100/length var light_pct = 0 var awake_pct = 0 if awake == 0 { light_pct = 100 - deep_pct } else { light_pct = light*100/length awake_pct = 100 - deep_pct - light_pct } self.deep_pct = deep_pct self.light_pct = light_pct self.awake_pct = awake_pct } override init() { super.init() } } //MARK: - 训练 enum TrainType: Int { case running = 0 case walking = 1 case swimming = 2 case hiking = 3 case elliptical_trainer = 4 case exercise_bike = 5 //5 case steppers = 6 case treadmill = 7 case bicycle = 8 case mountaineering = 9 case table_tennis = 10 //10 case badminton = 11 case yoga = 12 case rope_skipping = 13 case volleyball = 14 case football = 15 //15 case basketball = 16 case dance = 17 case spinningBike = 18 case sit_up = 19 case push_up = 20 //20 case pull_up = 21 case run_indoor = 33 } class TrainModel: Object { @Persisted var date: Date? = nil @Persisted private var typeRaw: Int = 0 @Persisted var length: Int = 0 //秒 @Persisted var calorie: Int = 0 //卡 @Persisted var mileage: Int = 0 //米 @Persisted var steps: Int = 0 var type: TrainType? { get { return TrainType(rawValue: typeRaw) } set { typeRaw = newValue?.rawValue ?? 0 } } var typeString: String? { get { switch type { case .running: return "跑步" case .walking: return "步行" case .swimming: return "游泳" case .hiking: return "徒步" case .elliptical_trainer: return "椭圆训练机" case .exercise_bike: return "健身车" case .steppers: return "踏步机" case .treadmill: return "跑步机" case .bicycle: return "自行车" case .mountaineering: return "登山" case .table_tennis: return "兵乓球" case .badminton: return "羽毛球" case .yoga: return "瑜伽" case .rope_skipping: return "跳绳" case .volleyball: return "排球" case .football: return "足球" case .basketball: return "篮球" case .dance: return "跳舞" case .spinningBike: return "动感单车" case .sit_up: return "仰卧起坐" case .push_up: return "俯卧撑" case .pull_up: return "引体向上" case .run_indoor: return "跑步" default: return "跑步" } } } convenience init(type: TrainType, date: Date, length: Int, calorie: Int, mileage: Int, steps: Int) { self.init() self.type = type self.date = date self.length = length self.calorie = calorie self.mileage = mileage self.steps = steps } class func toTrainModel(_ bytes: [UInt8]) -> TrainModel { let date = DateInRegion(year: Int(bytes[1])+2000, month: Int(bytes[2]), day: Int(bytes[3]), hour: Int(bytes[4]), minute: Int(bytes[5]), second: Int(bytes[6])).date let length = bytesToInt(Array(bytes[7..<11])) let mileage = bytesToInt(Array(bytes[11..<15])) let calorie = bytesToInt(Array(bytes[15..<19])) let steps = bytesToInt(Array(bytes[19..<23])) let type = TrainType(rawValue: Int(bytes[0])) ?? .walking let train = TrainModel(type: type, date: date, length: length, calorie: calorie, mileage: mileage, steps: steps) return train } func add() { // if let array = RealmTools.queryObjects(TrainModel.self, filter: "date = %@", [self.date ?? Date()]) as? [TrainModel] { // RealmTools.deleteList(array) // } // RealmTools.add(self) if let array = RealmTools.queryObjects(TrainModel.self, filter: "date = %@", [self.date ?? Date()]) as? [TrainModel], array.count > 0 { let model = array.last RealmTools.updateWithTranstion { (true) in // model?.typeRaw = self.typeRaw model?.date = self.date model?.length = self.length model?.calorie = self.calorie model?.mileage = self.mileage model?.steps = self.steps model?.type = self.type } } else { RealmTools.add(self) } } private func isEqual(_ train: TrainModel) -> Bool { if self.type == train.type { if self.date!.isInside(date: train.date!, granularity: .minute) { return true } } return false } class func addArray(_ array: [TrainModel]) { if array.count == 0 { return } for (i, train) in array.enumerated() { if train == array.first { train.add() } else { if !train.isEqual(array[i-1]) { train.add() } } } } class func getRecentData() -> [TrainModel] { guard let array = RealmTools.objectsWithPredicateAndSortedForPages(object: self, sortedKey: "date", isAssending: false, pageSize: 1) as? [TrainModel], array.count > 0 else { return [] } let date = array.last!.date return getTrainByDay(date!) } class func getTrainByDay(_ date: Date) -> [TrainModel] { return getHistoryTrain(startTime: date.dateAtStartOf(.day), endTime: date.dateAtEndOf(.day)-1.seconds) } class func getTrainByMonth(_ date: Date) -> [TrainModel] { return getHistoryTrain(startTime: date.dateAt(.startOfMonth), endTime: date.dateAt(.endOfMonth)-1.seconds) } private class func getHistoryTrain(startTime: Date, endTime: Date) -> [TrainModel] { guard let array = RealmTools.objectsWithPredicateAndSorted(object: self, predicate: NSPredicate(format: "date >= %@ AND date <= %@", argumentArray:[startTime, endTime]), sortedKey: "date") as? Array, array.count > 0 else { return [] } return array } } class MotionModel: Object { @Persisted var date: Date? = nil @Persisted private var typeRaw: Int = 0 @Persisted var length: Int = 0 //秒 @Persisted var calorie: Float = 0 //千卡 @Persisted var distance: Int = 0 //米 @Persisted var steps: Int = 0 @Persisted var altitude: Double = 0 //海拔 米 @Persisted var coordinateArray: String = "" //坐标array "xx|xx|xx" @Persisted var speedArray: String = "" //速度array "xx|xx|xx" @Persisted var stepCadenceArray: String = "" //步幅array "xx|xx|xx" @Persisted var altitudeArray: String = "" //海拔array var type: TrainType? { get { return TrainType(rawValue: typeRaw) } set { typeRaw = newValue?.rawValue ?? 0 } } var typeString: String? { get { switch type { case .running: return "跑步" case .walking: return "步行" case .swimming: return "游泳" case .hiking: return "徒步" case .elliptical_trainer: return "椭圆训练机" case .exercise_bike: return "健身车" case .steppers: return "踏步机" case .treadmill: return "跑步机" case .bicycle: return "自行车" case .mountaineering: return "登山" case .table_tennis: return "兵乓球" case .badminton: return "羽毛球" case .yoga: return "瑜伽" case .rope_skipping: return "跳绳" case .volleyball: return "排球" case .football: return "足球" case .basketball: return "篮球" case .dance: return "跳舞" case .spinningBike: return "动感单车" case .sit_up: return "仰卧起坐" case .push_up: return "俯卧撑" case .pull_up: return "引体向上" case .run_indoor: return "跑步" default: return "" } } } convenience init(type: TrainType, date: Date, length: Int, calorie: Float, distance: Int, steps: Int, altitude: Double, coordinateArray: String, speedArray: String, stepCadenceArray: String, altitudeArray: String) { self.init() self.type = type self.date = date self.length = length self.calorie = calorie self.distance = distance self.steps = steps self.altitude = altitude self.coordinateArray = coordinateArray self.speedArray = speedArray self.stepCadenceArray = stepCadenceArray self.altitudeArray = altitudeArray } func add() { if let array = RealmTools.queryObjects(MotionModel.self, filter: "date = %@", [self.date ?? Date()]) as? [MotionModel] { RealmTools.deleteList(array) } RealmTools.add(self) } private func isEqual(_ motion: MotionModel) -> Bool { if self.type == motion.type { if self.date!.isInside(date: motion.date!, granularity: .minute) { return true } } return false } class func addArray(_ array: [MotionModel]) { if array.count == 0 { return } for (i, motion) in array.enumerated() { if motion == array.first { motion.add() } else { if !motion.isEqual(array[i-1]) { motion.add() } } } } class func getRecentData() -> [MotionModel] { guard let array = RealmTools.objectsWithPredicateAndSortedForPages(object: self, sortedKey: "date", isAssending: false, pageSize: 1) as? [MotionModel], array.count > 0 else { return [] } let date = array.last!.date return getMotionByDay(date!) } class func getMotionByDay(_ date: Date) -> [MotionModel] { return getHistoryMotion(startTime: date.dateAtStartOf(.day), endTime: date.dateAtEndOf(.day)-1.seconds) } class func getMotionByMonth(_ date: Date) -> [MotionModel] { return getHistoryMotion(startTime: date.dateAt(.startOfMonth), endTime: date.dateAt(.endOfMonth)-1.seconds) } class func getMonthData(_ type: Int, date: Date) -> [MotionModel] { return getData(type, startTime: date.dateAt(.startOfMonth), endTime: date.dateAt(.endOfMonth)-1.seconds) } class func getData(_ type: Int, startTime: Date, endTime: Date) -> [MotionModel] { guard let array = RealmTools.objectsWithPredicateAndSorted(object: self, predicate: NSPredicate(format: "typeRaw = %@ AND date >= %@ AND date <= %@", argumentArray:[type, startTime, endTime]), sortedKey: "date") as? Array, array.count > 0 else { return [] } return array } private class func getHistoryMotion(startTime: Date, endTime: Date) -> [MotionModel] { guard let array = RealmTools.objectsWithPredicateAndSorted(object: self, predicate: NSPredicate(format: "date >= %@ AND date <= %@", argumentArray:[startTime, endTime]), sortedKey: "date") as? Array, array.count > 0 else { return [] } return array } } //MARK: - 压力 class PressureModel: Object { @Persisted var value: Int = -1 @Persisted var date: Date? = nil convenience init(value: Int, date: Date?) { self.init() self.value = value self.date = date } class func toPressureArray(_ bytes: [UInt8]) -> [PressureModel] { var pressureArray: [PressureModel] = [] // 将数组分成5个一组 let groupedArray = stride(from: 0, to: bytes.count, by: 5).map { Array(bytes[$0.. Bool { if self.value == pressure.value { if self.date!.isInside(date: pressure.date!, granularity: .minute) { return true } } return false } func realTimeAdd() { if let pressureArray = RealmTools.queryObjects(PressureModel.self) as? [PressureModel], let pressure = pressureArray.last { if !self.isEqual(pressure) { RealmTools.add(self) } } else { RealmTools.add(self) } } class func addArray(_ array: [PressureModel]) { if array.count == 0 { return } for (i, pressure) in array.enumerated() { if pressure == array.first { pressure.add() } else { if !pressure.isEqual(array[i-1]) { pressure.add() } } } } class func getRecentData(count: Int = 31) -> [PressureModel] { guard let array = RealmTools.objectsWithPredicateAndSortedForPages(object: self, sortedKey: "date", isAssending: false, pageSize: count) as? [PressureModel], array.count > 0 else { return [] } return array.reversed() } class func getPressureByDay(_ date: Date) -> [PressureModel] { // var pressureArray = getHistoryPressure(startTime: date.dateAtStartOf(.day), endTime: date.dateAtEndOf(.day)) // // guard let pressure = pressureArray.first, let firstDate = pressure.date else { // return [] // } // if firstDate.isAfterDate(firstDate.dateAtStartOf(.day)+1.hours, orEqual: true, granularity: .hour) { // pressureArray.insert(PressureModel(value: 0, date: firstDate.date.dateAtStartOf(.hour)-1.hours), at: 0) // } // if let lastPressure = pressureArray.last, (DateInRegion().date.isAfterDate(lastPressure.date!, orEqual: false, granularity: .minute) && DateInRegion().date.isInside(date: lastPressure.date!, granularity: .day)) { // pressureArray[pressureArray.count-1] = PressureModel(value: lastPressure.value, date: DateInRegion().date) // } // return pressureArray var pressureArray: [PressureModel] = [] for h in 0..<24 { if let hourPressure = getHistoryPressure(startTime: date.dateAtStartOf(.day)+h.hours, endTime: date.dateAtStartOf(.day)+(h+1).hours-1.seconds).last { pressureArray.append(PressureModel(value: hourPressure.value, date: date.dateAtStartOf(.day)+h.hours+1.hours)) } } if let pressure = pressureArray.first, let firstDate = pressure.date { if firstDate.isAfterDate(firstDate.dateAtStartOf(.day), orEqual: false, granularity: .hour) { pressureArray.insert(PressureModel(value: pressure.value, date: firstDate.date.dateAtStartOf(.day)), at: 0) } } // guard let pressure = pressureArray.first, let firstDate = pressure.date else { // return [] // } // if firstDate.isAfterDate(firstDate.dateAtStartOf(.day)+1.hours, orEqual: true, granularity: .hour) { // pressureArray.insert(PressureModel(value: 0, date: firstDate.date.dateAtStartOf(.hour)-1.hours), at: 0) // } return pressureArray } class func getAverageByDay(_ date: Date) -> (pressure: PressureModel, min: Int, max: Int) { let startDate = date.dateAt(.startOfDay) let array = getHistoryPressure(startTime: startDate, endTime: startDate+1.days-1.seconds) return (PressureModel(value: array.average(\.value), date: startDate), array.min(\.value)?.value ?? -1, array.max(\.value)?.value ?? -1) } class func getPressureByWeek(_ date: Date) -> (pressureArray: [PressureModel], min: [Int], max: [Int]) { var pressureArray: [PressureModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] let weekDays = date.compare(.isThisWeek) ? (DateInRegion()-1.days).weekday : 7 for i in 0.. 0 { pressureArray.append(PressureModel(value: array.average(\.value), date: startDate)) minArray.append(array.min(\.value)?.value ?? -1) maxArray.append(array.max(\.value)?.value ?? -1) } } return (pressureArray, minArray, maxArray) } class func getPressureByMonth(_ date: Date) -> (pressureArray: [PressureModel], min: [Int], max: [Int]) { var pressureArray: [PressureModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] let monthDays = date.compare(.isThisMonth) ? DateInRegion().day : date.monthDays for i in 0.. 0 { pressureArray.append(PressureModel(value: array.average(\.value), date: startDate)) minArray.append(array.min(\.value)?.value ?? -1) maxArray.append(array.max(\.value)?.value ?? -1) } } return (pressureArray, minArray, maxArray) } class func getPressureByYear(_ date: Date) -> (pressureArray: [PressureModel], min: [Int], max: [Int]) { var pressureArray: [PressureModel] = [] var minArray: [Int] = [] var maxArray: [Int] = [] let yearMonths = date.compare(.isThisYear) ? DateInRegion().month : 12 for i in 0.. 0 { pressureArray.append(PressureModel(value: array.average(\.value), date: startDate)) minArray.append(array.min(\.value)?.value ?? -1) maxArray.append(array.max(\.value)?.value ?? -1) } } return (pressureArray, minArray, maxArray) } private class func getHistoryPressure(startTime: Date, endTime: Date) -> [PressureModel] { guard let array = RealmTools.objectsWithPredicateAndSorted(object: self, predicate: NSPredicate(format: "date >= %@ AND date <= %@", argumentArray:[startTime, endTime]), sortedKey: "date") as? Array, array.count > 0 else { return [] } return array } class func updatePressure(date: Date, value: Int) { guard let array = RealmTools.queryObjects(self, filter: "date >= %@ AND date <= %@", [date.dateAtStartOf(.hour).date, date.dateAtEndOf(.hour).date]) as? Array, array.count > 0 else { return } let model = array.last RealmTools.updateWithTranstion { (true) in model?.value = value } } } //MARK: - 梅脱 class MettModel: Object { @Persisted var value: Int = -1 @Persisted var date: Date? = nil convenience init(value: Int, date: Date?) { self.init() self.value = value self.date = date } class func toMettArray(_ bytes: [UInt8]) -> [MettModel] { var mettArray: [MettModel] = [] let ndate = DateInRegion(year: Int(bytes[0])+2000, month: Int(bytes[1]), day: Int(bytes[2]), hour: Int(bytes[3]), minute: Int(bytes[4]), second: 0).date for i in 0..<7 { let date = (ndate-1.days).dateAt(.startOfWeek)+(i+1).days if date.isInPast { let mett = MettModel(value: Int(bytes[i+4]), date: (date)) mettArray.append(mett) } } return mettArray } func add() { let date = (self.date ?? Date()).dateAtStartOf(.day) if let a = RealmTools.queryObjects(MettModel.self, filter: "date >= %@ AND date <= %@", [date, date+1.days-1.seconds]) as? [MettModel] { RealmTools.deleteList(a) } RealmTools.add(self) } private func isEqual(_ mett: MettModel) -> Bool { if self.value == mett.value { if self.date!.isInside(date: mett.date!, granularity: .minute) { return true } } return false } func realTimeAdd() { if let mettArray = RealmTools.queryObjects(MettModel.self) as? [MettModel], let mett = mettArray.last { if !self.isEqual(mett) { RealmTools.add(self) } } else { RealmTools.add(self) } } class func addArray(_ array: [MettModel]) { if array.count == 0 { return } for (i, mett) in array.enumerated() { if mett == array.first { mett.add() } else { if !mett.isEqual(array[i-1]) { mett.add() } } } } class func getRecentData(count: Int = 7) -> [MettModel] { guard let array = RealmTools.objectsWithPredicateAndSortedForPages(object: self, sortedKey: "date", isAssending: false, pageSize: count) as? [MettModel], array.count > 0 else { return [] } return array.reversed() } class func getMettByWeek(_ date: Date) -> [MettModel] { var mettArray: [MettModel] = [] let weekDays = date.compare(.isThisWeek) ? (DateInRegion()-1.days).weekday : 7 for i in 0.. 0 { mettArray.append(MettModel(value: array.average(\.value), date: startDate)) } } return mettArray } class func getMettByMonth(_ date: Date) -> [MettModel] { var mettArray: [MettModel] = [] let monthDays = date.compare(.isThisMonth) ? DateInRegion().day : date.monthDays for i in 0.. 0 { mettArray.append(MettModel(value: array.sum(\.value), date: startDate)) } } return mettArray } class func getMettByYear(_ date: Date) -> [MettModel] { var mettArray: [MettModel] = [] let yearMonths = date.compare(.isThisYear) ? DateInRegion().month : 12 for i in 0.. 0 { mettArray.append(MettModel(value: array.sum(\.value), date: startDate)) } } return mettArray } private class func getHistoryMett(startTime: Date, endTime: Date) -> [MettModel] { guard let array = RealmTools.objectsWithPredicateAndSorted(object: self, predicate: NSPredicate(format: "date >= %@ AND date <= %@", argumentArray:[startTime, endTime]), sortedKey: "date") as? Array, array.count > 0 else { return [] } return array } } //勋章 class MedalModel: Object { @Persisted var type: String = "" //分类 @Persisted var title: String = "" //标题 @Persisted var detail: String = "" //详情 @Persisted var date: Date? = nil //获得日期 @Persisted var value: Float = 0 //当前值 @Persisted var subValue: Float = 0 @Persisted var lastDate: Date? = nil//最近统计日期 @Persisted var standard: Float = 0 //达标值 @Persisted var mode: String = "" //计算类型 // var required override init() { } convenience init(type: String, title: String, detail: String, standard: Float, mode: String) { self.init() self.type = type self.title = title self.detail = detail self.standard = standard self.mode = mode } class func create() { guard let medalArray = RealmTools.queryObjects(self) as? Array else { return } if medalArray.count == 0 { let plistPath = Bundle.main.path(forResource: "Medal", ofType: "plist") guard let plist = NSArray(contentsOfFile: plistPath!) as? [[String:Any]] else { return } for dic in plist { if let title = dic["title"] as? String, let detail = dic["detail"] as? String, let type = dic["type"] as? String, let standard = dic["standard"] as? Float, let mode = dic["mode"] as? String { // medals.append(MedalModel(type: type, title: title, detail: detail)) let medal = MedalModel(type: type, title: title, detail: detail, standard: standard, mode: mode) RealmTools.add(medal) } } } else { let user = UserInfo let version = "0.0.2" if user.medalVersion.checkVersion(version) { let plistPath = Bundle.main.path(forResource: "Medal", ofType: "plist") guard let plist = NSArray(contentsOfFile: plistPath!) as? [[String:Any]] else { return } for dic in plist { if let title = dic["title"] as? String, let detail = dic["detail"] as? String, let type = dic["type"] as? String, let standard = dic["standard"] as? Float, let mode = dic["mode"] as? String{ if let medals = RealmTools.queryObjects(MedalModel.self, filter: "title = %@", [title]) as? Array, medals.count > 0 { let m = medals.last RealmTools.updateWithTranstion { (true) in m?.detail = detail m?.type = type m?.standard = standard m?.mode = mode } } else { let medal = MedalModel(type: type, title: title, detail: detail, standard: standard, mode: mode) RealmTools.add(medal) } } } user.medalVersion = version AdminHelper.shared.updateUser(user) } } } // @Persisted var date: Date? = nil // @Persisted private var typeRaw: Int = 0 // @Persisted var length: Int = 0 //秒 // @Persisted var calorie: Float = 0 //千卡 // @Persisted var distance: Int = 0 //米 // @Persisted var steps: Int = 0 // @Persisted var altitude: Double = 0 //海拔 class func update(motion: MotionModel) { if let medalArray = RealmTools.queryObjects(self, filter: "date == nil") as? Array { for medal in medalArray { if medal.type == "步数" { if medal.mode == "单日" { let standard = Int(medal.standard) if medal.lastDate == nil { if motion.steps >= standard { RealmTools.updateWithTranstion { (true) in medal.date = DateInRegion().date } } else { RealmTools.updateWithTranstion { (true) in medal.lastDate = DateInRegion().date medal.value = Float(motion.steps) } } } else { if medal.lastDate!.isToday { let steps = Int(medal.value) + motion.steps if steps >= standard { RealmTools.updateWithTranstion { (true) in medal.date = DateInRegion().date } } else { RealmTools.updateWithTranstion { (true) in medal.lastDate = DateInRegion().date medal.value = Float(steps) } } } else { if motion.steps >= standard { RealmTools.updateWithTranstion { (true) in medal.date = DateInRegion().date } } else { RealmTools.updateWithTranstion { (true) in medal.lastDate = DateInRegion().date medal.value = Float(motion.steps) } } } } } else if medal.mode == "累计" { let standard = Int(medal.standard) var steps = Int(medal.value) steps += motion.steps var date: Date? = nil if steps >= standard { date = DateInRegion().date } RealmTools.updateWithTranstion { (true) in medal.value = Float(steps) medal.date = date } } else if medal.mode == "连续" { //每天1万 if medal.lastDate == nil { if motion.steps >= 10000 { RealmTools.updateWithTranstion { (true) in medal.value = 1.0 medal.subValue = Float(motion.steps) medal.lastDate = DateInRegion().date } } else { RealmTools.updateWithTranstion { (true) in medal.lastDate = DateInRegion().date medal.subValue = Float(motion.steps) } } } else { if (DateInRegion().date.dateAtStartOf(.day)-medal.lastDate!.dateAtStartOf(.day)).day == 1 { if medal.subValue < 10000 { RealmTools.updateWithTranstion { (true) in medal.lastDate = DateInRegion().date medal.subValue = Float(motion.steps) medal.value = motion.steps >= 10000 ? 1 : 0 } } else { var value = medal.value if motion.steps >= 10000 { value += 1 } if value >= medal.standard { RealmTools.updateWithTranstion { (true) in medal.value = value medal.date = DateInRegion().date } } else { RealmTools.updateWithTranstion { (true) in medal.lastDate = DateInRegion().date medal.subValue = Float(motion.steps) medal.value = value } } } } else if (DateInRegion().date.dateAtStartOf(.day)-medal.lastDate!.dateAtStartOf(.day)).day == 0 { let steps = Int(medal.subValue) + motion.steps var value = medal.value if steps >= 10000 { value += 1 if value >= medal.standard { RealmTools.updateWithTranstion { (true) in medal.value = value medal.date = DateInRegion().date } } else { RealmTools.updateWithTranstion { (true) in medal.lastDate = DateInRegion().date medal.subValue = Float(steps) medal.value = value } } } else { RealmTools.updateWithTranstion { (true) in medal.lastDate = DateInRegion().date medal.subValue = Float(steps) } } } else { if motion.steps >= 10000 { RealmTools.updateWithTranstion { (true) in medal.value = 1.0 medal.subValue = Float(motion.steps) medal.lastDate = DateInRegion().date } } else { RealmTools.updateWithTranstion { (true) in medal.lastDate = DateInRegion().date medal.subValue = Float(motion.steps) } } } } } } else if medal.type == "爬高" { var altitude = medal.value altitude += Float(motion.altitude) if altitude >= medal.standard { RealmTools.updateWithTranstion { (true) in medal.date = DateInRegion().date } } else { RealmTools.updateWithTranstion { (true) in medal.value = altitude } } } else if medal.type == "热量" { if medal.mode == "单日" { if medal.lastDate == nil { if motion.calorie >= medal.standard { RealmTools.updateWithTranstion { (true) in medal.date = DateInRegion().date } } else { RealmTools.updateWithTranstion { (true) in medal.lastDate = DateInRegion().date medal.value = Float(motion.calorie) } } } else { if medal.lastDate!.isToday { let calorie = medal.value + motion.calorie if calorie >= medal.standard { RealmTools.updateWithTranstion { (true) in medal.date = DateInRegion().date } } else { RealmTools.updateWithTranstion { (true) in medal.lastDate = DateInRegion().date medal.value = calorie } } } else { if motion.calorie >= medal.standard { RealmTools.updateWithTranstion { (true) in medal.date = DateInRegion().date } } else { RealmTools.updateWithTranstion { (true) in medal.lastDate = DateInRegion().date medal.value = Float(motion.calorie) } } } } } else if medal.mode == "累计" { let standard = medal.standard var calorie = medal.value calorie += motion.calorie var date: Date? = nil if calorie >= standard { date = DateInRegion().date } RealmTools.updateWithTranstion { (true) in medal.value = calorie medal.date = date } } } else if medal.type == "里程" { var distance = medal.value distance += Float(motion.distance) if distance >= medal.standard { RealmTools.updateWithTranstion { (true) in medal.date = DateInRegion().date } } else { RealmTools.updateWithTranstion { (true) in medal.value = distance } } } else if medal.type == "跑步" { if !(motion.type == .running || motion.type == .run_indoor) { return } if medal.mode == "单次" { let standard = Int(medal.standard) if medal.lastDate == nil { if motion.distance >= standard { RealmTools.updateWithTranstion { (true) in medal.date = DateInRegion().date } } else { RealmTools.updateWithTranstion { (true) in medal.lastDate = DateInRegion().date medal.value = Float(motion.distance) } } } else { if medal.lastDate!.isToday { let distance = Int(medal.value) + motion.distance if distance >= standard { RealmTools.updateWithTranstion { (true) in medal.date = DateInRegion().date } } else { RealmTools.updateWithTranstion { (true) in medal.lastDate = DateInRegion().date medal.value = Float(distance) } } } else { if motion.distance >= standard { RealmTools.updateWithTranstion { (true) in medal.date = DateInRegion().date } } else { RealmTools.updateWithTranstion { (true) in medal.lastDate = DateInRegion().date medal.value = Float(motion.distance) } } } } } else if medal.mode == "累计" { let standard = medal.standard var distance = medal.value distance += Float(motion.distance) var date: Date? = nil if distance >= standard { date = DateInRegion().date } RealmTools.updateWithTranstion { (true) in medal.value = distance medal.date = date } } else if medal.mode == "连续" { if medal.lastDate == nil { RealmTools.updateWithTranstion { (true) in medal.lastDate = DateInRegion().date medal.value = 1 } } else { if (DateInRegion().date.dateAtStartOf(.day)-medal.lastDate!.dateAtStartOf(.day)).day == 1 { var value = medal.value value += 1 if value >= medal.standard { RealmTools.updateWithTranstion { (true) in medal.value = value medal.date = DateInRegion().date } } else { RealmTools.updateWithTranstion { (true) in medal.lastDate = DateInRegion().date medal.value = value } } } else if (DateInRegion().date.dateAtStartOf(.day)-medal.lastDate!.dateAtStartOf(.day)).day == 0 { } else { RealmTools.updateWithTranstion { (true) in medal.value = 1.0 medal.lastDate = DateInRegion().date } } } } } } } } }