LastUpdatedView.swift (2030B)
1 import SwiftUI 2 3 struct LastUpdatedView: View { 4 let date: Date 5 let usesRoomierType: Bool 6 7 var body: some View { 8 TimelineView(.lastUpdated(from: date)) { context in 9 Text(text(now: context.date)) 10 .font(usesRoomierType ? .footnote : .caption) 11 .foregroundStyle(.secondary) 12 } 13 } 14 15 private func text(now: Date) -> String { 16 let elapsed = max(0, now.timeIntervalSince(date)) 17 if elapsed < 60 { 18 let seconds = max(1, Int(elapsed.rounded(.down))) 19 return "Last updated \(seconds) \(seconds == 1 ? "second" : "seconds") ago" 20 } 21 if elapsed < 60 * 60 { 22 let minutes = Int((elapsed / 60).rounded(.down)) 23 return "Last updated \(minutes) \(minutes == 1 ? "minute" : "minutes") ago" 24 } 25 if elapsed <= 48 * 60 * 60 { 26 let hours = Int((elapsed / (60 * 60)).rounded(.down)) 27 return "Last updated \(hours) \(hours == 1 ? "hour" : "hours") ago" 28 } 29 return "Last updated on \(date.formatted(.dateTime.day().month(.abbreviated).year()))" 30 } 31 } 32 33 private struct LastUpdatedSchedule: TimelineSchedule { 34 let anchor: Date 35 36 func entries(from startDate: Date, mode: TimelineScheduleMode) -> AnyIterator<Date> { 37 var next = startDate 38 return AnyIterator { 39 let current = next 40 let elapsed = max(0, current.timeIntervalSince(anchor)) 41 let step: TimeInterval 42 if elapsed < 60 { 43 step = 1 44 } else if elapsed < 60 * 60 { 45 step = 60 46 } else if elapsed <= 48 * 60 * 60 { 47 step = 60 * 60 48 } else { 49 return nil 50 } 51 next = current.addingTimeInterval(step) 52 return current 53 } 54 } 55 } 56 57 extension TimelineSchedule where Self == LastUpdatedSchedule { 58 static func lastUpdated(from date: Date) -> LastUpdatedSchedule { 59 LastUpdatedSchedule(anchor: date) 60 } 61 } 62