P2 Stream H: standalone TaskSuggestionsScreen

Port iOS TaskSuggestionsView as a standalone route reachable outside
onboarding. Uses shared suggestions API + accept/skip analytics in
non-onboarding variant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey T
2026-04-18 13:10:47 -05:00
parent 7d71408bcc
commit 19471d780d
19 changed files with 2161 additions and 3 deletions

View File

@@ -0,0 +1,59 @@
package com.tt.honeyDue.ui.haptics
import platform.UIKit.UIImpactFeedbackGenerator
import platform.UIKit.UIImpactFeedbackStyle
import platform.UIKit.UINotificationFeedbackGenerator
import platform.UIKit.UINotificationFeedbackType
/**
* iOS backend using [UIImpactFeedbackGenerator] and [UINotificationFeedbackGenerator]
* from UIKit. Generators are recreated per event since they are lightweight and
* iOS recommends preparing them lazily.
*
* Note: The primary iOS app uses SwiftUI haptics directly; this backend exists
* so shared Compose code that invokes [Haptics] still produces the correct
* tactile feedback when the Compose layer is exercised on iOS.
*/
class IosDefaultHapticBackend : HapticBackend {
override fun perform(event: HapticEvent) {
when (event) {
HapticEvent.LIGHT -> impact(UIImpactFeedbackStyle.UIImpactFeedbackStyleLight)
HapticEvent.MEDIUM -> impact(UIImpactFeedbackStyle.UIImpactFeedbackStyleMedium)
HapticEvent.HEAVY -> impact(UIImpactFeedbackStyle.UIImpactFeedbackStyleHeavy)
HapticEvent.SUCCESS -> notify(UINotificationFeedbackType.UINotificationFeedbackTypeSuccess)
HapticEvent.WARNING -> notify(UINotificationFeedbackType.UINotificationFeedbackTypeWarning)
HapticEvent.ERROR -> notify(UINotificationFeedbackType.UINotificationFeedbackTypeError)
}
}
private fun impact(style: UIImpactFeedbackStyle) {
val generator = UIImpactFeedbackGenerator(style = style)
generator.prepare()
generator.impactOccurred()
}
private fun notify(type: UINotificationFeedbackType) {
val generator = UINotificationFeedbackGenerator()
generator.prepare()
generator.notificationOccurred(type)
}
}
actual object Haptics {
private var backend: HapticBackend = IosDefaultHapticBackend()
actual fun light() = backend.perform(HapticEvent.LIGHT)
actual fun medium() = backend.perform(HapticEvent.MEDIUM)
actual fun heavy() = backend.perform(HapticEvent.HEAVY)
actual fun success() = backend.perform(HapticEvent.SUCCESS)
actual fun warning() = backend.perform(HapticEvent.WARNING)
actual fun error() = backend.perform(HapticEvent.ERROR)
actual fun setBackend(backend: HapticBackend) {
this.backend = backend
}
actual fun resetBackend() {
this.backend = IosDefaultHapticBackend()
}
}