Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion V2er/State/DataFlow/State/SettingState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,36 @@ struct SettingState: FluxState {
}

/// Check if we should attempt auto-checkin today
/// Uses 8:00 AM as the reset time instead of midnight
var shouldAutoCheckinToday: Bool {
guard autoCheckin else { return false }
guard let lastDate = lastCheckinDate else { return true }
return !Calendar.current.isDateInToday(lastDate)
return !Self.isSameCheckinDay(lastDate, Date())
}

/// Check if two dates are in the same "checkin day" (resets at 8:00 AM)
private static func isSameCheckinDay(_ date1: Date, _ date2: Date) -> Bool {
let calendar = Calendar.current
let resetHour = 8 // 8:00 AM
Comment on lines +62 to +63
Copy link

Copilot AI Dec 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation uses Calendar.current which respects the user's current timezone. This means the 8 AM reset time is based on the user's local timezone, not V2EX's server timezone (likely China Standard Time, UTC+8). If this is intentional to provide a better user experience, consider adding a comment to clarify this design decision. If the reset should align with V2EX's server time regardless of user location, consider using a fixed timezone instead.

Suggested change
let calendar = Calendar.current
let resetHour = 8 // 8:00 AM
// Use a fixed UTC+8 timezone (Asia/Shanghai) to match V2EX server time,
// so the 8:00 AM reset is consistent regardless of the user's local timezone.
let timeZone = TimeZone(identifier: "Asia/Shanghai")
?? TimeZone(secondsFromGMT: 8 * 60 * 60)
?? Calendar.current.timeZone
var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = timeZone
let resetHour = 8 // 8:00 AM (server time)

Copilot uses AI. Check for mistakes.

// Calculate the "checkin day" for each date
// If current hour < 8, it belongs to the previous calendar day's checkin period
func checkinDay(for date: Date) -> DateComponents {
let hour = calendar.component(.hour, from: date)
if hour < resetHour {
// Before 8 AM, belongs to previous day's checkin period
let previousDay = calendar.date(byAdding: .day, value: -1, to: date)!
Copy link

Copilot AI Dec 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Force unwrapping with ! could potentially crash if calendar.date(byAdding:value:to:) returns nil. While this is unlikely for day arithmetic, it's safer to use optional binding or provide a fallback. Consider using guard-let or nil-coalescing to handle edge cases gracefully.

Suggested change
let previousDay = calendar.date(byAdding: .day, value: -1, to: date)!
guard let previousDay = calendar.date(byAdding: .day, value: -1, to: date) else {
// Fallback to current date components if date calculation fails
return calendar.dateComponents([.year, .month, .day], from: date)
}

Copilot uses AI. Check for mistakes.
return calendar.dateComponents([.year, .month, .day], from: previousDay)
} else {
// 8 AM or later, belongs to current day's checkin period
return calendar.dateComponents([.year, .month, .day], from: date)
}
}

let day1 = checkinDay(for: date1)
let day2 = checkinDay(for: date2)

return day1.year == day2.year && day1.month == day2.month && day1.day == day2.day
}
}

Expand Down
Loading