start of graphs

release
Laurent 3 years ago
parent a7ec081bd9
commit 0e311d6134
  1. 14
      LeCountdown/Model/Model+Extensions.swift
  2. 12
      LeCountdown/Stats/Context+Calculations.swift
  3. 17
      LeCountdown/Stats/Stat.swift
  4. 4
      LeCountdown/Views/Stats/ActivityView.swift
  5. 45
      LeCountdown/Views/Stats/StatsView.swift

@ -67,6 +67,8 @@ extension Stopwatch {
extension Record { extension Record {
var count: Double { return 1.0 }
public override func didChangeValue(forKey key: String) { public override func didChangeValue(forKey key: String) {
super.didChangeValue(forKey: key) super.didChangeValue(forKey: key)
@ -99,6 +101,18 @@ extension Record {
} }
} }
func point(stat: Stat) -> Point? {
if let start {
switch stat {
case .count:
return Point(date: start, value: NSNumber(value: 1))
case .totalDuration, .averageDuration:
return Point(date: start, value: NSNumber(value: self.duration))
}
}
return nil
}
} }
extension Activity { extension Activity {

@ -36,7 +36,10 @@ extension NSManagedObjectContext {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Record") let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Record")
let basePredicate = NSPredicate(format: "start != nil")
var predicates: [NSPredicate] = [] var predicates: [NSPredicate] = []
predicates.append(basePredicate)
predicates.append(NSPredicate(format: "activity = %@", activity)) predicates.append(NSPredicate(format: "activity = %@", activity))
if let filter { if let filter {
predicates.append(filter.predicate) predicates.append(filter.predicate)
@ -74,7 +77,14 @@ extension NSManagedObjectContext {
} }
if let value { if let value {
let sv = StatValue(stat: stat, value: value) let request = Record.fetchRequest()
if let filter {
request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [basePredicate, filter.predicate])
}
let records: [Record] = try self.fetch(request)
let points = records.compactMap { $0.point(stat:stat) }
let sv = StatValue(stat: stat, value: value, records: points)
statValues.append(sv) statValues.append(sv)
} }
} }

@ -55,6 +55,22 @@ enum Stat: Int, CaseIterable {
return .doubleAttributeType return .doubleAttributeType
} }
} }
// var keyPath: KeyPath<Record, NSNumber> {
// switch self {
// case .count: return \Record.count
// case .averageDuration, .totalDuration: return \Record.duration
// }
// }
}
struct Point: Identifiable {
var date: Date
var value: NSNumber
var id: Date { date }
} }
struct StatValue: Identifiable { struct StatValue: Identifiable {
@ -63,6 +79,7 @@ struct StatValue: Identifiable {
var stat: Stat var stat: Stat
var value: NSDecimalNumber var value: NSDecimalNumber
var records: [Point] = []
var formattedValue: String { var formattedValue: String {

@ -43,11 +43,9 @@ struct ActivityView: View {
StatsView(activity: self.activity) StatsView(activity: self.activity)
.environment(\.managedObjectContext, viewContext) .environment(\.managedObjectContext, viewContext)
.background(.red)
.foregroundColor(.white)
RecordsView(activity: self.activity) RecordsView(activity: self.activity)
.environment(\.managedObjectContext, viewContext) .environment(\.managedObjectContext, viewContext)
.frame(maxWidth: .infinity) // .frame(maxWidth: .infinity)
} }
} }

@ -7,6 +7,7 @@
import SwiftUI import SwiftUI
import CoreData import CoreData
import Charts
class StatModel: ObservableObject { class StatModel: ObservableObject {
@ -59,11 +60,11 @@ struct StatsView: View {
} else { } else {
VStack(alignment: .leading) { VStack(alignment: .leading) {
ForEach(self.model.statValues) { statValue in ForEach(self.model.statValues) { statValue in
StatView(name: statValue.stat.localizedName, value: statValue.formattedValue).padding(.vertical) StatGraphView(statValue: statValue)
// .padding(.vertical)
} }
} }
} }
Spacer()
} }
.onAppear() { .onAppear() {
self.model.compute(activity: self.activity, filter: self.filter) self.model.compute(activity: self.activity, filter: self.filter)
@ -75,13 +76,43 @@ struct StatsView: View {
struct StatView: View { struct StatView: View {
var name: String var statValue: StatValue
var value: String
var body: some View { var body: some View {
VStack(alignment: .leading) { VStack(alignment: .leading) {
Text(self.name.uppercased()).font(.footnote) Text(self.statValue.stat.localizedName.uppercased())
Text(self.value).font(.system(.title, weight: .bold)) .font(.footnote)
Text(self.statValue.formattedValue)
.font(.system(.title, weight: .bold))
}
}
}
struct StatGraphView: View {
var statValue: StatValue
var body: some View {
VStack {
HStack {
Text(self.statValue.stat.localizedName.uppercased())
// .font(.footnote)
Text(self.statValue.formattedValue)
// .font(.system(.title, weight: .bold))
}
Chart(self.statValue.records) { point in
let stat: Stat = self.statValue.stat
switch stat {
case .count, .totalDuration:
BarMark(x: .value("name", point.date, unit: .month),
y: .value("value", point.value.doubleValue))
default:
LineMark(x: .value("name", point.date, unit: .month),
y: .value("value", point.value.doubleValue))
}
}
} }
} }
@ -89,7 +120,7 @@ struct StatView: View {
struct StatView_Previews: PreviewProvider { struct StatView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
StatView(name: "Duration", value: "3") StatView(statValue: StatValue(stat: .count, value: NSDecimalNumber(integerLiteral: 3)))
} }
} }

Loading…
Cancel
Save