// // DateSection.swift // AutoCatCore // // Created by Selim Mustafaev on 27.03.2022. // import Foundation import SwiftDate import DifferenceKit public protocol Dated { var addedAt: Date { get } var updatedAt: Date { get } } public class DateSection: DifferentiableSection { private var timestamp: Double = 0 public private(set) var header: String public private(set) var elements: [T] public init(timestamp: Double, items: [T]) { let formatter = DateFormatter() formatter.dateStyle = .medium formatter.timeStyle = .medium let now = DateInRegion(Date(), region: Region.current) let monthStart = now.dateAtStartOf(.month) let weekStart = now.dateAtStartOf(.weekOfMonth) let date = Date(timeIntervalSince1970: timestamp) let dateInRegion = DateInRegion(date, region: Region.current) if dateInRegion.isToday { self.header = NSLocalizedString("Today", comment: "") } else if dateInRegion.isYesterday { self.header = NSLocalizedString("Yesterday", comment: "") } else if dateInRegion.isAfterDate(weekStart, granularity: .day) { formatter.dateFormat = "EEEE" self.header = formatter.string(from: date) } else if dateInRegion.isAfterDate(monthStart, orEqual: false, granularity: .day) { formatter.dateStyle = .medium formatter.timeStyle = .none self.header = formatter.string(from: date) } else { formatter.dateFormat = "LLLL yyyy" self.header = formatter.string(from: date) } self.timestamp = timestamp self.elements = items } public func append(_ element: T) { self.elements.append(element) } // MARK: - DifferentiableSection public required init(source: DateSection, elements: C) where C : Collection, C.Element == T { self.timestamp = source.timestamp self.header = source.header self.elements = Array(elements) } public var differenceIdentifier: String { return header } public func isContentEqual(to source: DateSection) -> Bool { return differenceIdentifier == source.differenceIdentifier } } extension DateSection: Hashable { public static func == (lhs: DateSection, rhs: DateSection) -> Bool { return lhs.timestamp == rhs.timestamp && lhs.elements == rhs.elements } public func hash(into hasher: inout Hasher) { hasher.combine(self.timestamp) hasher.combine(self.elements) } } extension RandomAccessCollection where Element: Dated & Hashable & Differentiable { public func groupedByDate() -> [DateSection] { let now = Date() let monthStart = now.dateAtStartOf(.month) var sectionsIndices: [TimeInterval: Int] = [:] var sectionsArray: [DateSection] = [] for item in self { let date = item.updatedAt let dateInRegion = DateInRegion(date, region: Region.current) var key = dateInRegion.dateAtStartOf(.day).timeIntervalSince1970 if date.isBeforeDate(monthStart, orEqual: false, granularity: .day) { key = dateInRegion.dateAtStartOf(.month).timeIntervalSince1970 } if let index = sectionsIndices[key] { sectionsArray[index].append(item) } else { sectionsArray.append(DateSection(timestamp: key, items: [item])) sectionsIndices[key] = sectionsArray.count - 1 } } return sectionsArray } }