Files
Reflect/Shared/Date+Extensions.swift
Trey t f822927e98 Add interactive widget voting and fix warnings/bugs
Widget Features:
- Add inline voting to timeline widget when no entry exists for today
- Show random prompt from notification strings in voting mode
- Update vote widget to use simple icon style for selection
- Make stats bar full width in voted state view
- Add Localizable.strings to widget extension target

Bug Fixes:
- Fix inverted date calculation in InsightsViewModel streak logic
- Replace force unwraps with safe optional handling in widgets
- Replace fatalError calls with graceful error handling
- Fix CSV import safety in SettingsView

Warning Fixes:
- Add @retroactive to Color and Date extension conformances
- Update deprecated onChange(of:perform:) to new syntax
- Replace deprecated applicationIconBadgeNumber with setBadgeCount
- Replace deprecated UIApplication.shared.windows API
- Add @preconcurrency for Swift 6 protocol conformances
- Add missing widget family cases to switch statement
- Remove unused variables and #warning directives

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 16:23:12 -06:00

104 lines
3.3 KiB
Swift

//
// Date+Extensions.swift
// Feels (iOS)
//
// Created by Trey Tartt on 2/19/22.
//
import Foundation
extension Date: @retroactive RawRepresentable {
public var rawValue: String {
self.timeIntervalSinceReferenceDate.description
}
public init?(rawValue: String) {
self = Date(timeIntervalSinceReferenceDate: Double(rawValue) ?? 0.0)
}
var startOfDay: Date {
return Calendar.current.startOfDay(for: self)
}
var startOfMonth: Date {
let calendar = Calendar(identifier: .gregorian)
let components = calendar.dateComponents([.year, .month], from: self)
return calendar.date(from: components)!
}
var endOfDay: Date {
var components = DateComponents()
components.day = 1
components.second = -1
return Calendar.current.date(byAdding: components, to: startOfDay)!
}
var endOfMonth: Date {
var components = DateComponents()
components.month = 1
components.second = -1
return Calendar(identifier: .gregorian).date(byAdding: components, to: startOfMonth)!
}
func toLocalTime() -> Date {
let timezone = TimeZone.current
let seconds = TimeInterval(timezone.secondsFromGMT(for: self))
return Date(timeInterval: seconds, since: self)
}
var weekday: Int {
Calendar.current.component(.weekday, from: self)
}
var firstDayOfTheMonth: Date {
Calendar.current.dateComponents([.calendar, .year,.month], from: self).date!
}
static public func dates(from fromDate: Date, toDate: Date, includingToDate: Bool = false) -> [Date] {
var dates: [Date] = []
var date = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: fromDate)!
let toDate = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: toDate)!
if includingToDate {
while date <= toDate {
dates.append(date)
guard let newDate = Calendar.current.date(byAdding: .day, value: 1, to: date) else { break }
date = newDate
}
} else {
while date < toDate {
dates.append(date)
guard let newDate = Calendar.current.date(byAdding: .day, value: 1, to: date) else { break }
date = newDate
}
}
return dates
}
static func dateRange(monthInt: Int, yearInt: Int) -> (startDate: Date, endDate: Date) {
var dateComponents = DateComponents()
dateComponents.year = yearInt
dateComponents.month = monthInt
dateComponents.day = 3
dateComponents.hour = 12
var userCalendar = Calendar(identifier: .gregorian)
userCalendar.timeZone = TimeZone(secondsFromGMT: 0)!
let someDateTime = userCalendar.date(from: dateComponents)!
let startDate = someDateTime.startOfMonth
var endDate = someDateTime.endOfMonth
endDate = Calendar.current.date(byAdding: .hour, value: -8, to: endDate)!
return (startDate, endDate)
}
func formattedDate() -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM dd, yyyy"
return dateFormatter.string(from: self)
}
}