field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | README | LICENSE

TeraCalendarPresentation.swift (3476B)


      1 import Foundation
      2 
      3 struct TeraCalendarPresentation {
      4   var locale: Locale = .current
      5   var timeZone: TimeZone = .current
      6 
      7   func summary(_ timing: TeraCalendarTiming) -> String {
      8     switch timing {
      9     case let .dateBased(start, end):
     10       let format = TeraCivilDateFormat(locale: locale)
     11       guard let end else { return "All day, \(format.string(start))" }
     12       guard end > start, let last = end.previousDay else { return "Date unavailable" }
     13       let range = last == start ? format.string(start) : "\(format.string(start)) – \(format.string(last))"
     14       return "All day, \(range)"
     15     case let .timeBased(start, end, startZone, endZone):
     16       guard end == nil || end.map({ $0 > start }) == true else { return "Date unavailable" }
     17       var parts = [instant(start, zone: timeZone, label: "Starts")]
     18       if let end {
     19         parts.append(instant(end, zone: timeZone, label: "Ends"))
     20       }
     21       parts.append("Display time zone: \(timeZone.identifier)")
     22       if let startZone {
     23         parts.append(sourceInstant(start, zoneID: startZone, label: "Event start"))
     24       }
     25       if let end, let endZone {
     26         parts.append(sourceInstant(end, zoneID: endZone, label: "Event end"))
     27       }
     28       return parts.joined(separator: "; ")
     29     }
     30   }
     31 
     32   func authoredSummary(_ seconds: UInt64) -> String {
     33     instant(seconds, zone: timeZone, label: "Posted")
     34   }
     35 
     36   func authoredDate(_ seconds: UInt64) -> Date? {
     37     displayDate(seconds, zone: timeZone)
     38   }
     39 
     40   private func displayDate(_ seconds: UInt64, zone: TimeZone) -> Date? {
     41     guard let date = TeraCalendarTiming.presentationInstant(seconds) else { return nil }
     42     var calendar = Calendar(identifier: .gregorian)
     43     calendar.timeZone = zone
     44     return (1 ... 9999).contains(calendar.component(.year, from: date)) ? date : nil
     45   }
     46 
     47   private func sourceInstant(_ seconds: UInt64, zoneID: String, label: String) -> String {
     48     guard zoneID.utf8.count <= 255, let zone = TimeZone(identifier: zoneID) else { return "Date unavailable" }
     49     return "\(instant(seconds, zone: zone, label: label)) (\(zoneID))"
     50   }
     51 
     52   private func instant(_ seconds: UInt64, zone: TimeZone, label: String) -> String {
     53     guard let date = displayDate(seconds, zone: zone) else { return "Date unavailable" }
     54     var calendar = Calendar(identifier: .gregorian)
     55     calendar.timeZone = zone
     56     let format = DateFormatter()
     57     format.locale = locale
     58     format.calendar = calendar
     59     format.timeZone = zone
     60     format.dateStyle = .medium
     61     format.timeStyle = .long
     62     return "\(label): \(format.string(from: date))"
     63   }
     64 }
     65 
     66 extension TeraTodayCard {
     67   var accessibilitySummary: String {
     68     accessibilitySummary(locale: .current, timeZone: .current)
     69   }
     70 
     71   func accessibilitySummary(locale: Locale, timeZone: TimeZone) -> String {
     72     var parts = [type.label, "by \(authorName)"]
     73     if let title {
     74       parts.append(title)
     75     }
     76     if !content.isEmpty {
     77       parts.append(content)
     78     }
     79     if let calendarTiming {
     80       parts.append(TeraCalendarPresentation(locale: locale, timeZone: timeZone).summary(calendarTiming))
     81     }
     82     let food = TeraFoodPresentation(locale: locale)
     83     if let price = food.price(self) {
     84       parts.append(price)
     85     }
     86     if let quantity = food.quantity(self) {
     87       parts.append(quantity)
     88     }
     89     if lifecycle != .active {
     90       parts.append(lifecycle.rawValue)
     91     }
     92     if let localOperationState {
     93       parts.append(localOperationState)
     94     }
     95     return parts.joined(separator: ", ")
     96   }
     97 }