Add interactive widget voting and fix warnings/bugs

Widget Features:
- Add inline voting to timeline widget when no entry exists for today
- Show random prompt from notification strings in voting mode
- Update vote widget to use simple icon style for selection
- Make stats bar full width in voted state view
- Add Localizable.strings to widget extension target

Bug Fixes:
- Fix inverted date calculation in InsightsViewModel streak logic
- Replace force unwraps with safe optional handling in widgets
- Replace fatalError calls with graceful error handling
- Fix CSV import safety in SettingsView

Warning Fixes:
- Add @retroactive to Color and Date extension conformances
- Update deprecated onChange(of:perform:) to new syntax
- Replace deprecated applicationIconBadgeNumber with setBadgeCount
- Replace deprecated UIApplication.shared.windows API
- Add @preconcurrency for Swift 6 protocol conformances
- Add missing widget family cases to switch statement
- Remove unused variables and #warning directives

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-12-10 16:23:12 -06:00
parent aaaf04f05e
commit f822927e98
20 changed files with 317 additions and 220 deletions

View File

@@ -176,51 +176,51 @@ struct CreateWidgetView: View {
VStack(alignment: .center) {
Text(String(localized: "create_widget_background_color"))
ColorPicker("", selection: $customWidget.bgColor)
.onChange(of: customWidget.mouthColor, perform: { newValue in
.onChange(of: customWidget.bgColor) {
EventLogger.log(event: "create_widget_view_update_background_color")
})
}
.labelsHidden()
}
.frame(minWidth: 0, maxWidth: .infinity)
VStack(alignment: .center) {
Text(String(localized: "create_widget_inner_color"))
ColorPicker("", selection: $customWidget.innerColor)
.onChange(of: customWidget.mouthColor, perform: { newValue in
.onChange(of: customWidget.innerColor) {
EventLogger.log(event: "create_widget_view_update_inner_color")
})
}
.labelsHidden()
}
.frame(minWidth: 0, maxWidth: .infinity)
VStack(alignment: .center) {
Text(String(localized: "create_widget_face_outline_color"))
ColorPicker("", selection: $customWidget.circleStrokeColor)
.onChange(of: customWidget.mouthColor, perform: { newValue in
.onChange(of: customWidget.circleStrokeColor) {
EventLogger.log(event: "create_widget_view_update_outline_color")
})
}
.labelsHidden()
}
.frame(minWidth: 0, maxWidth: .infinity)
}
HStack(spacing: 0) {
VStack(alignment: .center) {
Text(String(localized: "create_widget_view_left_eye_color"))
ColorPicker("", selection: $customWidget.leftEyeColor)
.onChange(of: customWidget.mouthColor, perform: { newValue in
.onChange(of: customWidget.leftEyeColor) {
EventLogger.log(event: "create_widget_view_update_left_eye_color")
})
}
.labelsHidden()
}
.frame(minWidth: 0, maxWidth: .infinity)
VStack(alignment: .center) {
Text(String(localized: "create_widget_view_right_eye_color"))
ColorPicker("", selection: $customWidget.rightEyeColor)
.onChange(of: customWidget.mouthColor, perform: { newValue in
.onChange(of: customWidget.rightEyeColor) {
EventLogger.log(event: "create_widget_view_update_right_eye_color")
})
}
.labelsHidden()
}
.frame(minWidth: 0, maxWidth: .infinity)
@@ -228,9 +228,9 @@ struct CreateWidgetView: View {
VStack(alignment: .center) {
Text(String(localized: "create_widget_view_mouth_color"))
ColorPicker("", selection: $customWidget.mouthColor)
.onChange(of: customWidget.mouthColor, perform: { newValue in
.onChange(of: customWidget.mouthColor) {
EventLogger.log(event: "create_widget_view_update_mouth_color")
})
}
.labelsHidden()
}
.frame(minWidth: 0, maxWidth: .infinity)