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:
@@ -8,6 +8,7 @@
|
||||
import SwiftUI
|
||||
import SwiftData
|
||||
import Charts
|
||||
import TipKit
|
||||
|
||||
struct DayViewConstants {
|
||||
static let maxHeaderHeight = 200.0
|
||||
@@ -30,7 +31,6 @@ struct DayView: View {
|
||||
// MARK: edit row properties
|
||||
@State private var showingSheet = false
|
||||
@State private var selectedEntry: MoodEntryModel?
|
||||
@State private var showEntryDetail = false
|
||||
//
|
||||
|
||||
// MARK: ?? properties
|
||||
@@ -53,25 +53,16 @@ struct DayView: View {
|
||||
.sheet(isPresented: $showingSheet) {
|
||||
SettingsView()
|
||||
}
|
||||
.onChange(of: selectedEntry) { _, newEntry in
|
||||
if newEntry != nil {
|
||||
showEntryDetail = true
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $showEntryDetail, onDismiss: {
|
||||
selectedEntry = nil
|
||||
}) {
|
||||
if let entry = selectedEntry {
|
||||
EntryDetailView(
|
||||
entry: entry,
|
||||
onMoodUpdate: { newMood in
|
||||
viewModel.update(entry: entry, toMood: newMood)
|
||||
},
|
||||
onDelete: {
|
||||
viewModel.update(entry: entry, toMood: .missing)
|
||||
}
|
||||
)
|
||||
}
|
||||
.sheet(item: $selectedEntry) { entry in
|
||||
EntryDetailView(
|
||||
entry: entry,
|
||||
onMoodUpdate: { newMood in
|
||||
viewModel.update(entry: entry, toMood: newMood)
|
||||
},
|
||||
onDelete: {
|
||||
viewModel.update(entry: entry, toMood: .missing)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
.padding([.top])
|
||||
@@ -107,6 +98,7 @@ struct DayView: View {
|
||||
AddMoodHeaderView(addItemHeaderClosure: { (mood, date) in
|
||||
viewModel.add(mood: mood, forDate: date, entryType: .header)
|
||||
})
|
||||
.widgetVotingTip()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import SwiftUI
|
||||
import SwiftData
|
||||
import WidgetKit
|
||||
|
||||
@MainActor
|
||||
class DayViewViewModel: ObservableObject {
|
||||
@@ -60,12 +61,28 @@ class DayViewViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
public func add(mood: Mood, forDate date: Date, entryType: EntryType) {
|
||||
DataController.shared.add(mood: mood, forDate: date, entryType: entryType)
|
||||
MoodLogger.shared.logMood(mood, for: date, entryType: entryType)
|
||||
}
|
||||
|
||||
public func update(entry: MoodEntryModel, toMood mood: Mood) {
|
||||
if !DataController.shared.update(entryDate: entry.forDate, withMood: mood) {
|
||||
print("Failed to update mood entry")
|
||||
return
|
||||
}
|
||||
|
||||
// Sync to HealthKit for past day updates
|
||||
guard mood != .missing && mood != .placeholder else { return }
|
||||
|
||||
let healthKitEnabled = GroupUserDefaults.groupDefaults.bool(forKey: UserDefaultsStore.Keys.healthKitEnabled.rawValue)
|
||||
if healthKitEnabled {
|
||||
Task {
|
||||
try? await HealthKitManager.shared.saveMood(mood, for: entry.forDate)
|
||||
}
|
||||
}
|
||||
|
||||
// Reload widgets asynchronously to avoid UI delay
|
||||
Task { @MainActor in
|
||||
WidgetCenter.shared.reloadAllTimelines()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user