Update Neon colors and show color circles in theme picker
- Update NeonMoodTint to use synthwave colors matching Neon voting style (cyan, lime, yellow, orange, magenta) - Replace text label with 5 color circles in theme preview Colors row - Remove unused textColor customization code and picker views - Add .id(moodTint) to Month/Year views for color refresh - Clean up various unused color-related code 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -175,76 +175,80 @@ class LiveActivityScheduler: ObservableObject {
|
||||
return calendar.date(byAdding: .hour, value: 5, to: ratingDateTime)
|
||||
}
|
||||
|
||||
/// Check if user has rated today
|
||||
func hasRatedToday() -> Bool {
|
||||
/// Cached streak data to avoid redundant calculations
|
||||
private var cachedStreakData: (streak: Int, todaysMood: Mood?, votingDate: Date)?
|
||||
|
||||
/// Get streak data using efficient batch query (cached per voting date)
|
||||
private func getStreakData() -> (streak: Int, todaysMood: Mood?) {
|
||||
let votingDate = ShowBasedOnVoteLogics.getCurrentVotingDate(onboardingData: UserDefaultsStore.getOnboarding())
|
||||
let dayStart = Calendar.current.startOfDay(for: votingDate)
|
||||
let dayEnd = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: dayStart)!
|
||||
|
||||
// Return cached data if still valid for current voting date
|
||||
if let cached = cachedStreakData,
|
||||
Calendar.current.isDate(cached.votingDate, inSameDayAs: votingDate) {
|
||||
return (cached.streak, cached.todaysMood)
|
||||
}
|
||||
|
||||
// Calculate and cache
|
||||
#if WIDGET_EXTENSION
|
||||
let entry = WidgetDataProvider.shared.getData(startDate: dayStart, endDate: dayEnd, includedDays: []).first
|
||||
#else
|
||||
let entry = DataController.shared.getData(startDate: dayStart, endDate: dayEnd, includedDays: []).first
|
||||
#endif
|
||||
return entry != nil && entry?.mood != .missing && entry?.mood != .placeholder
|
||||
}
|
||||
// Widget extension uses its own data provider
|
||||
let calendar = Calendar.current
|
||||
let dayStart = calendar.startOfDay(for: votingDate)
|
||||
guard let yearAgo = calendar.date(byAdding: .day, value: -365, to: dayStart) else {
|
||||
return (0, nil)
|
||||
}
|
||||
|
||||
let entries = WidgetDataProvider.shared.getData(startDate: yearAgo, endDate: votingDate, includedDays: [])
|
||||
.filter { $0.mood != .missing && $0.mood != .placeholder }
|
||||
|
||||
guard !entries.isEmpty else { return (0, nil) }
|
||||
|
||||
let datesWithEntries = Set(entries.map { calendar.startOfDay(for: $0.forDate) })
|
||||
let todaysEntry = entries.first { calendar.isDate($0.forDate, inSameDayAs: votingDate) }
|
||||
let todaysMood = todaysEntry?.mood
|
||||
|
||||
/// Calculate current streak
|
||||
func calculateStreak() -> Int {
|
||||
var streak = 0
|
||||
var checkDate = ShowBasedOnVoteLogics.getCurrentVotingDate(onboardingData: UserDefaultsStore.getOnboarding())
|
||||
|
||||
// Check if current voting date has an entry
|
||||
let currentDayStart = Calendar.current.startOfDay(for: checkDate)
|
||||
let currentDayEnd = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: currentDayStart)!
|
||||
#if WIDGET_EXTENSION
|
||||
let currentEntry = WidgetDataProvider.shared.getData(startDate: currentDayStart, endDate: currentDayEnd, includedDays: []).first
|
||||
#else
|
||||
let currentEntry = DataController.shared.getData(startDate: currentDayStart, endDate: currentDayEnd, includedDays: []).first
|
||||
#endif
|
||||
|
||||
// If no entry for current voting date, start counting from previous day
|
||||
// This ensures the streak shows correctly even if user hasn't rated today yet
|
||||
if currentEntry == nil || currentEntry?.mood == .missing || currentEntry?.mood == .placeholder {
|
||||
checkDate = Calendar.current.date(byAdding: .day, value: -1, to: checkDate)!
|
||||
var checkDate = votingDate
|
||||
if !datesWithEntries.contains(dayStart) {
|
||||
checkDate = calendar.date(byAdding: .day, value: -1, to: checkDate) ?? checkDate
|
||||
}
|
||||
|
||||
while true {
|
||||
let dayStart = Calendar.current.startOfDay(for: checkDate)
|
||||
let dayEnd = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: dayStart)!
|
||||
|
||||
#if WIDGET_EXTENSION
|
||||
let entry = WidgetDataProvider.shared.getData(startDate: dayStart, endDate: dayEnd, includedDays: []).first
|
||||
#else
|
||||
let entry = DataController.shared.getData(startDate: dayStart, endDate: dayEnd, includedDays: []).first
|
||||
#endif
|
||||
|
||||
if let entry = entry, entry.mood != .missing && entry.mood != .placeholder {
|
||||
let checkDayStart = calendar.startOfDay(for: checkDate)
|
||||
if datesWithEntries.contains(checkDayStart) {
|
||||
streak += 1
|
||||
checkDate = Calendar.current.date(byAdding: .day, value: -1, to: checkDate)!
|
||||
checkDate = calendar.date(byAdding: .day, value: -1, to: checkDate) ?? checkDate
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return streak
|
||||
cachedStreakData = (streak, todaysMood, votingDate)
|
||||
return (streak, todaysMood)
|
||||
#else
|
||||
let result = DataController.shared.calculateStreak(from: votingDate)
|
||||
cachedStreakData = (result.streak, result.todaysMood, votingDate)
|
||||
return result
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Check if user has rated today
|
||||
func hasRatedToday() -> Bool {
|
||||
return getStreakData().todaysMood != nil
|
||||
}
|
||||
|
||||
/// Calculate current streak
|
||||
func calculateStreak() -> Int {
|
||||
return getStreakData().streak
|
||||
}
|
||||
|
||||
/// Get today's mood if logged
|
||||
func getTodaysMood() -> Mood? {
|
||||
let votingDate = ShowBasedOnVoteLogics.getCurrentVotingDate(onboardingData: UserDefaultsStore.getOnboarding())
|
||||
let dayStart = Calendar.current.startOfDay(for: votingDate)
|
||||
let dayEnd = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: dayStart)!
|
||||
return getStreakData().todaysMood
|
||||
}
|
||||
|
||||
#if WIDGET_EXTENSION
|
||||
let entry = WidgetDataProvider.shared.getData(startDate: dayStart, endDate: dayEnd, includedDays: []).first
|
||||
#else
|
||||
let entry = DataController.shared.getData(startDate: dayStart, endDate: dayEnd, includedDays: []).first
|
||||
#endif
|
||||
if let entry = entry, entry.mood != .missing && entry.mood != .placeholder {
|
||||
return entry.mood
|
||||
}
|
||||
return nil
|
||||
/// Invalidate cached streak data (call when mood is logged)
|
||||
func invalidateCache() {
|
||||
cachedStreakData = nil
|
||||
}
|
||||
|
||||
/// Schedule Live Activity based on current time and rating time
|
||||
|
||||
Reference in New Issue
Block a user