main
Laurent 3 years ago
parent 5bee77c3b0
commit 2a89996d8f
  1. 8
      LeCountdown.xcodeproj/project.pbxproj
  2. 3
      LeCountdown/Model/NSManagedContext+Extensions.swift
  3. 13
      LeCountdown/Views/Stats/ActivityView.swift
  4. 10
      LeCountdown/Views/Stats/GraphsView.swift
  5. 6
      LeCountdown/Views/Stats/RecordsView.swift

@ -136,7 +136,7 @@
C4BA2B3A299F838000CB4FBA /* Model+SharedExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B39299F838000CB4FBA /* Model+SharedExtensions.swift */; }; C4BA2B3A299F838000CB4FBA /* Model+SharedExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B39299F838000CB4FBA /* Model+SharedExtensions.swift */; };
C4BA2B3B299F838000CB4FBA /* Model+SharedExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B39299F838000CB4FBA /* Model+SharedExtensions.swift */; }; C4BA2B3B299F838000CB4FBA /* Model+SharedExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B39299F838000CB4FBA /* Model+SharedExtensions.swift */; };
C4BA2B3C299F838000CB4FBA /* Model+SharedExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B39299F838000CB4FBA /* Model+SharedExtensions.swift */; }; C4BA2B3C299F838000CB4FBA /* Model+SharedExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B39299F838000CB4FBA /* Model+SharedExtensions.swift */; };
C4BA2B3E299FC86800CB4FBA /* StatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B3D299FC86800CB4FBA /* StatsView.swift */; }; C4BA2B3E299FC86800CB4FBA /* GraphsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B3D299FC86800CB4FBA /* GraphsView.swift */; };
C4BA2B43299FCB2B00CB4FBA /* RecordsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B42299FCB2B00CB4FBA /* RecordsView.swift */; }; C4BA2B43299FCB2B00CB4FBA /* RecordsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B42299FCB2B00CB4FBA /* RecordsView.swift */; };
C4BA2B49299FCE0C00CB4FBA /* IntervalGroup+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B47299FCE0C00CB4FBA /* IntervalGroup+CoreDataProperties.swift */; }; C4BA2B49299FCE0C00CB4FBA /* IntervalGroup+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B47299FCE0C00CB4FBA /* IntervalGroup+CoreDataProperties.swift */; };
C4BA2B4A299FCE0C00CB4FBA /* IntervalGroup+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B47299FCE0C00CB4FBA /* IntervalGroup+CoreDataProperties.swift */; }; C4BA2B4A299FCE0C00CB4FBA /* IntervalGroup+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BA2B47299FCE0C00CB4FBA /* IntervalGroup+CoreDataProperties.swift */; };
@ -357,7 +357,7 @@
C4BA2B30299F759700CB4FBA /* DefaultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultView.swift; sourceTree = "<group>"; }; C4BA2B30299F759700CB4FBA /* DefaultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultView.swift; sourceTree = "<group>"; };
C4BA2B35299F82FB00CB4FBA /* Fakes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fakes.swift; sourceTree = "<group>"; }; C4BA2B35299F82FB00CB4FBA /* Fakes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fakes.swift; sourceTree = "<group>"; };
C4BA2B39299F838000CB4FBA /* Model+SharedExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Model+SharedExtensions.swift"; sourceTree = "<group>"; }; C4BA2B39299F838000CB4FBA /* Model+SharedExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Model+SharedExtensions.swift"; sourceTree = "<group>"; };
C4BA2B3D299FC86800CB4FBA /* StatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsView.swift; sourceTree = "<group>"; }; C4BA2B3D299FC86800CB4FBA /* GraphsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphsView.swift; sourceTree = "<group>"; };
C4BA2B42299FCB2B00CB4FBA /* RecordsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordsView.swift; sourceTree = "<group>"; }; C4BA2B42299FCB2B00CB4FBA /* RecordsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordsView.swift; sourceTree = "<group>"; };
C4BA2B46299FCD8B00CB4FBA /* LeCountdown.0.6.1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = LeCountdown.0.6.1.xcdatamodel; sourceTree = "<group>"; }; C4BA2B46299FCD8B00CB4FBA /* LeCountdown.0.6.1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = LeCountdown.0.6.1.xcdatamodel; sourceTree = "<group>"; };
C4BA2B47299FCE0C00CB4FBA /* IntervalGroup+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IntervalGroup+CoreDataProperties.swift"; sourceTree = "<group>"; }; C4BA2B47299FCE0C00CB4FBA /* IntervalGroup+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IntervalGroup+CoreDataProperties.swift"; sourceTree = "<group>"; };
@ -675,7 +675,7 @@
C438C80E29828B8600BF3EF9 /* ActivitiesView.swift */, C438C80E29828B8600BF3EF9 /* ActivitiesView.swift */,
C4BA2B6029A3C02400CB4FBA /* ActivityView.swift */, C4BA2B6029A3C02400CB4FBA /* ActivityView.swift */,
C4BA2B42299FCB2B00CB4FBA /* RecordsView.swift */, C4BA2B42299FCB2B00CB4FBA /* RecordsView.swift */,
C4BA2B3D299FC86800CB4FBA /* StatsView.swift */, C4BA2B3D299FC86800CB4FBA /* GraphsView.swift */,
); );
path = Stats; path = Stats;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1028,7 +1028,7 @@
C4E5D66629B73AED008E7465 /* StartTimerIntent.swift in Sources */, C4E5D66629B73AED008E7465 /* StartTimerIntent.swift in Sources */,
C4BA2AD62993F62700CB4FBA /* SoundSelectionView.swift in Sources */, C4BA2AD62993F62700CB4FBA /* SoundSelectionView.swift in Sources */,
C498E5A5299152B400E90DE0 /* GreenCheckmarkView.swift in Sources */, C498E5A5299152B400E90DE0 /* GreenCheckmarkView.swift in Sources */,
C4BA2B3E299FC86800CB4FBA /* StatsView.swift in Sources */, C4BA2B3E299FC86800CB4FBA /* GraphsView.swift in Sources */,
C4F8B1B8298AC81D005C86A5 /* CountdownDialView.swift in Sources */, C4F8B1B8298AC81D005C86A5 /* CountdownDialView.swift in Sources */,
C473C2F929A8DC0A0056B38A /* LaunchWidgetAttributes.swift in Sources */, C473C2F929A8DC0A0056B38A /* LaunchWidgetAttributes.swift in Sources */,
C445FA922987CC8A0054D761 /* Sound.swift in Sources */, C445FA922987CC8A0054D761 /* Sound.swift in Sources */,

@ -16,13 +16,14 @@ extension NSManagedObjectContext {
return self.object(with: objectId) return self.object(with: objectId)
} }
func distinct(entityName: String, attributes: [String]) throws -> [Any] { func distinct(entityName: String, attributes: [String], predicate: NSPredicate? = nil) throws -> [Any] {
let request = NSFetchRequest<NSFetchRequestResult>(entityName: entityName) let request = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
request.entity = NSEntityDescription.entity(forEntityName: entityName, in: self) request.entity = NSEntityDescription.entity(forEntityName: entityName, in: self)
request.returnsDistinctResults = true request.returnsDistinctResults = true
request.resultType = .dictionaryResultType request.resultType = .dictionaryResultType
request.predicate = predicate
if let entity = request.entity { if let entity = request.entity {
let entityProperties = entity.propertiesByName let entityProperties = entity.propertiesByName
var properties = [NSPropertyDescription]() var properties = [NSPropertyDescription]()

@ -29,11 +29,11 @@ struct ActivityView: View {
List { List {
StatsView(activity: self.activity, GraphsView(activity: self.activity,
timeFrame: self.selectedTimeFrame) timeFrame: self.selectedTimeFrame)
.environment(\.managedObjectContext, viewContext) .environment(\.managedObjectContext, viewContext)
let filters = self.selectedTimeFrame.filters(context: viewContext) let filters = self.selectedTimeFrame.filters(context: viewContext, activity: activity)
RecordsView(activity: self.activity, filters: filters) RecordsView(activity: self.activity, filters: filters)
.environment(\.managedObjectContext, viewContext) .environment(\.managedObjectContext, viewContext)
} }
@ -59,14 +59,16 @@ enum TimeFrame: Int, Identifiable, CaseIterable {
} }
} }
func filters(context: NSManagedObjectContext) -> [Filter] { func filters(context: NSManagedObjectContext, activity: Activity) -> [Filter] {
let predicate = NSPredicate(format: "activity = %@", activity)
do { do {
switch self { switch self {
case .all: case .all:
return [.none] return [.none]
case .year: case .year:
let distinct = try context.distinct(entityName: "Record", attributes: ["year"]) let distinct = try context.distinct(entityName: "Record", attributes: ["year"], predicate: predicate)
if let yearsMap = distinct as? [[String : Int]] { if let yearsMap = distinct as? [[String : Int]] {
let years = yearsMap.compactMap { $0.first?.value } let years = yearsMap.compactMap { $0.first?.value }
return years.map { Filter.year($0) } return years.map { Filter.year($0) }
@ -74,7 +76,7 @@ enum TimeFrame: Int, Identifiable, CaseIterable {
Logger.w("Could not cast \(distinct) as [Int]") Logger.w("Could not cast \(distinct) as [Int]")
} }
case .month: case .month:
let distinct = try context.distinct(entityName: "Record", attributes: ["year", "month"]) let distinct = try context.distinct(entityName: "Record", attributes: ["year", "month"], predicate: predicate)
if let distinctMonths = distinct as? [[String : Int]] { if let distinctMonths = distinct as? [[String : Int]] {
let months = distinctMonths.compactMap { let months = distinctMonths.compactMap {
@ -95,7 +97,6 @@ enum TimeFrame: Int, Identifiable, CaseIterable {
Logger.error(error) Logger.error(error)
} }
return [] return []
} }
} }

@ -43,7 +43,7 @@ class StatModel: ObservableObject {
} }
struct StatsView: View { struct GraphsView: View {
var activity: Activity var activity: Activity
var timeFrame: TimeFrame var timeFrame: TimeFrame
@ -62,7 +62,7 @@ struct StatsView: View {
} else { } else {
VStack(alignment: .leading) { VStack(alignment: .leading) {
ForEach(self.model.statValues) { statValue in ForEach(self.model.statValues) { statValue in
StatGraphView(statValue: statValue, timeFrame: self.timeFrame) GraphView(statValue: statValue, timeFrame: self.timeFrame)
// .padding(.vertical) // .padding(.vertical)
} }
} }
@ -92,7 +92,7 @@ struct StatView: View {
} }
struct StatGraphView: View { struct GraphView: View {
var statValue: StatValue var statValue: StatValue
var timeFrame: TimeFrame var timeFrame: TimeFrame
@ -130,7 +130,7 @@ struct StatGraphView_Previews: PreviewProvider {
Point(date: Date(timeIntervalSince1970: 100000), value: 1)] Point(date: Date(timeIntervalSince1970: 100000), value: 1)]
static var previews: some View { static var previews: some View {
StatGraphView(statValue: StatValue(stat: .count, value: NSDecimalNumber(integerLiteral: 3), points: points), timeFrame: .all) GraphView(statValue: StatValue(stat: .count, value: NSDecimalNumber(integerLiteral: 3), points: points), timeFrame: .all)
} }
} }
@ -142,7 +142,7 @@ struct StatView_Previews: PreviewProvider {
struct StatsView_Previews: PreviewProvider { struct StatsView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
StatsView(activity: Activity.fake(context: PersistenceController.preview.container.viewContext), GraphsView(activity: Activity.fake(context: PersistenceController.preview.container.viewContext),
timeFrame: .all) timeFrame: .all)
} }
} }

@ -13,7 +13,7 @@ class RecordsModel: ObservableObject {
@Published var filters: [Filter] = [] @Published var filters: [Filter] = []
func loadFilters(activity: Activity, timeFrame: TimeFrame, context: NSManagedObjectContext) { func loadFilters(activity: Activity, timeFrame: TimeFrame, context: NSManagedObjectContext) {
self.filters = timeFrame.filters(context: context) self.filters = timeFrame.filters(context: context, activity: activity)
} }
} }
@ -27,12 +27,12 @@ struct RecordsView: View {
var body: some View { var body: some View {
Section { // Section {
ForEach(self.filters) { filter in ForEach(self.filters) { filter in
RecordsSectionView(activity: self.activity, filter: filter) RecordsSectionView(activity: self.activity, filter: filter)
.environment(\.managedObjectContext, viewContext) .environment(\.managedObjectContext, viewContext)
} }
} // }
} }
} }

Loading…
Cancel
Save