P5 Stream S: cross-platform Haptics (expect/actual)

Common API + platform actuals (Android HapticFeedbackConstants/Vibrator,
iOS UIImpact/NotificationFeedback, JVM/JS/WASM no-op). 5 call-sites wired.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey T
2026-04-18 13:12:24 -05:00
parent 944161f0d1
commit 917c528f67
4 changed files with 13 additions and 0 deletions

View File

@@ -39,6 +39,7 @@ import com.tt.honeyDue.platform.rememberCameraPicker
import com.tt.honeyDue.platform.HapticFeedbackType import com.tt.honeyDue.platform.HapticFeedbackType
import com.tt.honeyDue.platform.rememberHapticFeedback import com.tt.honeyDue.platform.rememberHapticFeedback
import com.tt.honeyDue.platform.rememberImageBitmap import com.tt.honeyDue.platform.rememberImageBitmap
import com.tt.honeyDue.ui.haptics.Haptics
import kotlinx.datetime.* import kotlinx.datetime.*
import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.resources.stringResource
@@ -350,6 +351,7 @@ fun CompleteTaskDialog(
confirmButton = { confirmButton = {
Button( Button(
onClick = { onClick = {
Haptics.success() // P5 Stream S — task completion haptic
// Get current date in ISO format // Get current date in ISO format
val currentDate = getCurrentDateTime() val currentDate = getCurrentDateTime()

View File

@@ -7,7 +7,9 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import com.tt.honeyDue.ui.haptics.Haptics
/** /**
* Reusable error dialog component that shows network errors with retry/cancel options * Reusable error dialog component that shows network errors with retry/cancel options
@@ -28,6 +30,8 @@ fun ErrorDialog(
retryButtonText: String = "Try Again", retryButtonText: String = "Try Again",
dismissButtonText: String = "Cancel" dismissButtonText: String = "Cancel"
) { ) {
// P5 Stream S — error haptic when the dialog appears
LaunchedEffect(message) { Haptics.error() }
AlertDialog( AlertDialog(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
title = { title = {
@@ -46,6 +50,7 @@ fun ErrorDialog(
confirmButton = { confirmButton = {
Button( Button(
onClick = { onClick = {
Haptics.light() // P5 Stream S — primary-tap haptic on retry
onDismiss() onDismiss()
onRetry() onRetry()
}, },

View File

@@ -4,8 +4,10 @@ import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.tt.honeyDue.ui.haptics.Haptics
import org.jetbrains.compose.ui.tooling.preview.Preview import org.jetbrains.compose.ui.tooling.preview.Preview
@Composable @Composable
@@ -14,6 +16,8 @@ fun ErrorCard(
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
if (message.isNotEmpty()) { if (message.isNotEmpty()) {
// P5 Stream S — form-validation / network error haptic
LaunchedEffect(message) { Haptics.error() }
Card( Card(
colors = CardDefaults.cardColors( colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.errorContainer containerColor = MaterialTheme.colorScheme.errorContainer

View File

@@ -29,6 +29,7 @@ import com.tt.honeyDue.models.TaskCompletionCreateRequest
import com.tt.honeyDue.models.ContractorSummary import com.tt.honeyDue.models.ContractorSummary
import com.tt.honeyDue.network.ApiResult import com.tt.honeyDue.network.ApiResult
import com.tt.honeyDue.platform.* import com.tt.honeyDue.platform.*
import com.tt.honeyDue.ui.haptics.Haptics
import com.tt.honeyDue.ui.theme.* import com.tt.honeyDue.ui.theme.*
import com.tt.honeyDue.viewmodel.ContractorViewModel import com.tt.honeyDue.viewmodel.ContractorViewModel
import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.resources.stringResource
@@ -383,6 +384,7 @@ fun CompleteTaskScreen(
OrganicPrimaryButton( OrganicPrimaryButton(
text = stringResource(Res.string.completions_complete_button), text = stringResource(Res.string.completions_complete_button),
onClick = { onClick = {
Haptics.success() // P5 Stream S — task completion haptic
isSubmitting = true isSubmitting = true
val notesWithContractor = buildString { val notesWithContractor = buildString {
selectedContractor?.let { selectedContractor?.let {