Add Apple platform features and UX improvements
- Add HealthKit State of Mind sync for mood entries - Add Live Activity with streak display and rating time window - Add App Shortcuts/Siri integration for voice mood logging - Add TipKit hints for feature discovery - Add centralized MoodLogger for consistent side effects - Add reminder time setting in Settings with time picker - Fix duplicate notifications when changing reminder time - Fix Live Activity streak showing 0 when not yet rated today - Fix slow tap response in entry detail mood selection - Update widget timeline to refresh at rating time - Sync widgets when reminder time changes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,9 @@ enum EntryType: Int, Codable {
|
||||
case filledInMissing = 4
|
||||
case notification = 5
|
||||
case header = 6
|
||||
case siri = 7
|
||||
case controlCenter = 8
|
||||
case liveActivity = 9
|
||||
}
|
||||
|
||||
// MARK: - SwiftData Model
|
||||
|
||||
@@ -6,15 +6,27 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import WidgetKit
|
||||
|
||||
final class OnboardingDataDataManager: ObservableObject {
|
||||
static let shared = OnboardingDataDataManager()
|
||||
|
||||
|
||||
@Published public private(set) var savedOnboardingData = UserDefaultsStore.getOnboarding()
|
||||
|
||||
|
||||
public func updateOnboardingData(onboardingData: OnboardingData) {
|
||||
let onboardingData = UserDefaultsStore.saveOnboarding(onboardingData: onboardingData)
|
||||
savedOnboardingData = onboardingData
|
||||
LocalNotification.scheduleReminder(atTime: onboardingData.date)
|
||||
|
||||
// Update Live Activity schedule when rating time changes
|
||||
Task { @MainActor in
|
||||
LiveActivityScheduler.shared.onRatingTimeUpdated()
|
||||
}
|
||||
|
||||
// Force sync UserDefaults to app group before reloading widgets
|
||||
GroupUserDefaults.groupDefaults.synchronize()
|
||||
|
||||
// Reload widgets so they show the correct view for new time
|
||||
WidgetCenter.shared.reloadAllTimelines()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@ protocol PersonalityPackable {
|
||||
|
||||
enum PersonalityPack: Int, CaseIterable {
|
||||
case Default = 0
|
||||
case Rude = 1
|
||||
case MotivationalCoach = 2
|
||||
case ZenMaster = 3
|
||||
case BestFriend = 4
|
||||
case DataAnalyst = 5
|
||||
// case Rude = 1
|
||||
case MotivationalCoach = 1
|
||||
case ZenMaster = 2
|
||||
case BestFriend = 3
|
||||
case DataAnalyst = 4
|
||||
|
||||
func randomPushNotificationStrings() -> (title: String, body: String) {
|
||||
let onboarding = UserDefaultsStore.getOnboarding()
|
||||
@@ -33,12 +33,12 @@ enum PersonalityPack: Int, CaseIterable {
|
||||
case (.Default, .Previous):
|
||||
return (DefaultTitles.notificationTitles.randomElement()!,
|
||||
DefaultTitles.notificationBodyYesterday.randomElement()!)
|
||||
case (.Rude, .Today):
|
||||
return (RudeTitles.notificationTitles.randomElement()!,
|
||||
RudeTitles.notificationBodyToday.randomElement()!)
|
||||
case (.Rude, .Previous):
|
||||
return (RudeTitles.notificationTitles.randomElement()!,
|
||||
RudeTitles.notificationBodyYesterday.randomElement()!)
|
||||
// case (.Rude, .Today):
|
||||
// return (RudeTitles.notificationTitles.randomElement()!,
|
||||
// RudeTitles.notificationBodyToday.randomElement()!)
|
||||
// case (.Rude, .Previous):
|
||||
// return (RudeTitles.notificationTitles.randomElement()!,
|
||||
// RudeTitles.notificationBodyYesterday.randomElement()!)
|
||||
case (.MotivationalCoach, .Today):
|
||||
return (MotivationalCoachTitles.notificationTitles.randomElement()!,
|
||||
MotivationalCoachTitles.notificationBodyToday.randomElement()!)
|
||||
@@ -70,8 +70,8 @@ enum PersonalityPack: Int, CaseIterable {
|
||||
switch self {
|
||||
case .Default:
|
||||
return DefaultTitles.title
|
||||
case .Rude:
|
||||
return RudeTitles.title
|
||||
// case .Rude:
|
||||
// return RudeTitles.title
|
||||
case .MotivationalCoach:
|
||||
return MotivationalCoachTitles.title
|
||||
case .ZenMaster:
|
||||
@@ -86,7 +86,7 @@ enum PersonalityPack: Int, CaseIterable {
|
||||
var icon: String {
|
||||
switch self {
|
||||
case .Default: return "face.smiling"
|
||||
case .Rude: return "flame"
|
||||
// case .Rude: return "flame"
|
||||
case .MotivationalCoach: return "figure.run"
|
||||
case .ZenMaster: return "leaf"
|
||||
case .BestFriend: return "heart"
|
||||
@@ -97,7 +97,7 @@ enum PersonalityPack: Int, CaseIterable {
|
||||
var description: String {
|
||||
switch self {
|
||||
case .Default: return "Friendly and supportive"
|
||||
case .Rude: return "Snarky with attitude"
|
||||
// case .Rude: return "Snarky with attitude"
|
||||
case .MotivationalCoach: return "High energy pump-up vibes"
|
||||
case .ZenMaster: return "Calm and mindful"
|
||||
case .BestFriend: return "Casual and supportive"
|
||||
|
||||
@@ -96,6 +96,7 @@ class UserDefaultsStore {
|
||||
case dayViewStyle
|
||||
case privacyLockEnabled
|
||||
case healthKitEnabled
|
||||
case healthKitSyncEnabled
|
||||
|
||||
case contentViewCurrentSelectedHeaderViewBackDays
|
||||
case contentViewHeaderTag
|
||||
|
||||
Reference in New Issue
Block a user