This is easy using CoreData + SwiftUI.
The code below is for iOS15+ but you can do the same thing with an NSFetchedResultsController
or NSFetchRequest
/ @FetchRequest
and then group it. But it will require a bit of effort to stay real time.
Also, the code below is meant to work with the standard Apple code for a CoreData project. The only thing I changed in PersistenceController
is setting a random day for the timestamp
newItem.timestamp = Date().addingTimeInterval(60*60*24*Double(Int.random(in: -10...10)))
This is a simple graph
import SwiftUI
@available(iOS 15.0, *)
struct DayChart: View {
@SectionedFetchRequest(entity: Item.entity(), sectionIdentifier: \.completionDate, sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)], predicate: nil, animation: Animation.linear)
var sections: SectionedFetchResults<String, Item>
@State var maxCount: Int = 1
let spacing: CGFloat = 3
var body: some View {
VStack{
GeometryReader{ geo in
HStack(alignment: .bottom, spacing: spacing){
ForEach(sections){section in
VStack{
Text(section.count.description)
Rectangle()
.foregroundColor(.blue)
.onAppear(){
maxCount = max(maxCount,section.count)
}
Text(section.id.description).minimumScaleFactor(0.5)
.lineLimit(2)
}.frame(width: (geo.size.width/CGFloat(sections.count) - spacing),height: geo.size.height * CGFloat(CGFloat(section.count)/CGFloat(maxCount)))
}
}
}
}.padding(.leading, spacing)
}
}
@available(iOS 15.0, *)
struct DayChart_Previews: PreviewProvider {
static var previews: some View {
DayChart().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}
}
extension Item{
//This is the variable that determines your section/column/completion date
@objc
var completionDate: String{
if self.timestamp != nil{
let dateFormatter: DateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd\nMMM"
return dateFormatter.string(from: self.timestamp!)
}else{
return ""
}
}
}