Harden iOS app with audit fixes, UI consistency, and sheet race condition fixes
Applies verified fixes from deep audit (concurrency, performance, security, accessibility), standardizes CRUD form buttons to Add/Save pattern, removes .drawingGroup() that broke search bar TextFields, and converts vulnerable .sheet(isPresented:) + if-let patterns to safe presentation to prevent blank white modals. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,28 @@ import SwiftUI
|
||||
import AppIntents
|
||||
|
||||
// MARK: - Date Formatting Helper
|
||||
|
||||
/// Cached formatters to avoid repeated allocation in widget rendering
|
||||
private enum WidgetDateFormatters {
|
||||
static let dateOnly: DateFormatter = {
|
||||
let f = DateFormatter()
|
||||
f.dateFormat = "yyyy-MM-dd"
|
||||
return f
|
||||
}()
|
||||
|
||||
static let iso8601WithFractional: ISO8601DateFormatter = {
|
||||
let f = ISO8601DateFormatter()
|
||||
f.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
||||
return f
|
||||
}()
|
||||
|
||||
static let iso8601: ISO8601DateFormatter = {
|
||||
let f = ISO8601DateFormatter()
|
||||
f.formatOptions = [.withInternetDateTime]
|
||||
return f
|
||||
}()
|
||||
}
|
||||
|
||||
/// Parses date strings in either yyyy-MM-dd or ISO8601 (RFC3339) format
|
||||
/// and returns a user-friendly string like "Today" or "in X days"
|
||||
private func formatWidgetDate(_ dateString: String) -> String {
|
||||
@@ -17,20 +39,15 @@ private func formatWidgetDate(_ dateString: String) -> String {
|
||||
var date: Date?
|
||||
|
||||
// Try parsing as yyyy-MM-dd first
|
||||
let dateOnlyFormatter = DateFormatter()
|
||||
dateOnlyFormatter.dateFormat = "yyyy-MM-dd"
|
||||
date = dateOnlyFormatter.date(from: dateString)
|
||||
date = WidgetDateFormatters.dateOnly.date(from: dateString)
|
||||
|
||||
// Try parsing as ISO8601 (RFC3339) if that fails
|
||||
if date == nil {
|
||||
let isoFormatter = ISO8601DateFormatter()
|
||||
isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
||||
date = isoFormatter.date(from: dateString)
|
||||
date = WidgetDateFormatters.iso8601WithFractional.date(from: dateString)
|
||||
|
||||
// Try without fractional seconds
|
||||
if date == nil {
|
||||
isoFormatter.formatOptions = [.withInternetDateTime]
|
||||
date = isoFormatter.date(from: dateString)
|
||||
date = WidgetDateFormatters.iso8601.date(from: dateString)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,9 +196,11 @@ struct Provider: AppIntentTimelineProvider {
|
||||
let tasks = CacheManager.getUpcomingTasks()
|
||||
let isInteractive = WidgetActionManager.shared.shouldShowInteractiveWidget()
|
||||
|
||||
// Update every 30 minutes (more frequent for interactive widgets)
|
||||
// Use a longer refresh interval during overnight hours (11pm-6am)
|
||||
let currentDate = Date()
|
||||
let nextUpdate = Calendar.current.date(byAdding: .minute, value: 30, to: currentDate)!
|
||||
let hour = Calendar.current.component(.hour, from: currentDate)
|
||||
let refreshMinutes = (hour >= 23 || hour < 6) ? 120 : 30
|
||||
let nextUpdate = Calendar.current.date(byAdding: .minute, value: refreshMinutes, to: currentDate)!
|
||||
let entry = SimpleEntry(
|
||||
date: currentDate,
|
||||
configuration: configuration,
|
||||
|
||||
Reference in New Issue
Block a user