115 lines
3.7 KiB
Swift
115 lines
3.7 KiB
Swift
//
|
|
// 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<T: Hashable & Differentiable>: 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<C>(source: DateSection<T>, 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<T>) -> Bool {
|
|
return differenceIdentifier == source.differenceIdentifier
|
|
}
|
|
}
|
|
|
|
extension DateSection: Hashable {
|
|
|
|
public static func == (lhs: DateSection<T>, rhs: DateSection<T>) -> 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<Element>] {
|
|
let now = Date()
|
|
let monthStart = now.dateAtStartOf(.month)
|
|
var sectionsIndices: [TimeInterval: Int] = [:]
|
|
var sectionsArray: [DateSection<Element>] = []
|
|
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<Element>(timestamp: key, items: [item]))
|
|
sectionsIndices[key] = sectionsArray.count - 1
|
|
}
|
|
}
|
|
|
|
return sectionsArray
|
|
}
|
|
}
|