UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: List with dynamic sections by date

Forums > SwiftUI

Hi guys,

I'm losing my mind a bit trying to figure out how to create some sections based on the day component of a day but no luck. I have tried multiple methods but I'm getting stuck every time, I would appreciate any hint. Last time I tried with a dictionary and I realise that the flaw lies in the Date proprety having such a granularity that every moment is different from the other but I can't think of anything else. Thank you!

Struct:

struct Scan: Identifiable, Codable, Comparable {
    var id = UUID()
    var scanDate = Date()
    let content: String

    static func < (lhs: Scan, rhs: Scan) -> Bool {
        return lhs.scanDate < rhs.scanDate
    }
}

View:

struct History: View {
    @EnvironmentObject var modelData: ModelData

    var groupedByDate: [Date: [Scan]] {
        Dictionary(grouping: modelData.scans, by: {$0.scanDate})
    }

    var headers: [Date] {
        groupedByDate.map({ $0.key }).sorted()
    }

    var body: some View {
        List {
            ForEach(headers, id: \.self) { header in
                Section(header: Text(header, style: .date)) {
                    ForEach(groupedByDate[header]!) { scan in
                        Text(scan.content)
                    }
                }
            }
        }
    }

Screenshot with the result :( https://postimg.cc/0KjChTHT

edit, I tried with scanDate as a computed proprety as well but it changes the value to all my previous saved object also :(

struct Scan: Identifiable, Codable, Comparable {
    var id = UUID()
    var scanDate: Date {
        let now = Date()
        let components = Calendar.current.dateComponents([.year, .month, .day], from: now)
        let date = Calendar.current.date(from: components)
        return date!
    }
    let content: String

    static func < (lhs: Scan, rhs: Scan) -> Bool {
        return lhs.scanDate < rhs.scanDate
    }
}

Edit2: Solved it by refering to another proprety outside the computed proprety like this:

struct Scan: Identifiable, Codable, Comparable {
    var id = UUID()
    var now = Date()
    var scanDate: Date {
        let components = Calendar.current.dateComponents([.year, .month, .day], from: now)
        let date = Calendar.current.date(from: components)
        return date ?? Date()
    }
    let content: String

    static func < (lhs: Scan, rhs: Scan) -> Bool {
        return lhs.scanDate < rhs.scanDate
    }
}

3      

hi,

you might consider turning all raw dates into the start of the day date:

var scanDate: Date { Calendar.current.startOfDay(for: date) }

now your dictionary grouping by scanDate should work OK.

  • one caveat: i think that the start of the date of this post (17-Apr-2021) is 12:00:00 AM, which might be shown 16-Apr-2021. if that's the case, just add 1 (second) to startOfDay(for: date) before returning the scanDate.

hope that helps,

DMG

4      

Turns out you're right, it works this way too. Thank you DMG! edit: it's not the case to add one second after 12.00 AM

3      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.