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

View File

@@ -7,7 +7,9 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
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
@@ -28,6 +30,8 @@ fun ErrorDialog(
retryButtonText: String = "Try Again",
dismissButtonText: String = "Cancel"
) {
// P5 Stream S — error haptic when the dialog appears
LaunchedEffect(message) { Haptics.error() }
AlertDialog(
onDismissRequest = onDismiss,
title = {
@@ -46,6 +50,7 @@ fun ErrorDialog(
confirmButton = {
Button(
onClick = {
Haptics.light() // P5 Stream S — primary-tap haptic on retry
onDismiss()
onRetry()
},

View File

@@ -4,8 +4,10 @@ import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.tt.honeyDue.ui.haptics.Haptics
import org.jetbrains.compose.ui.tooling.preview.Preview
@Composable
@@ -14,6 +16,8 @@ fun ErrorCard(
modifier: Modifier = Modifier
) {
if (message.isNotEmpty()) {
// P5 Stream S — form-validation / network error haptic
LaunchedEffect(message) { Haptics.error() }
Card(
colors = CardDefaults.cardColors(
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.network.ApiResult
import com.tt.honeyDue.platform.*
import com.tt.honeyDue.ui.haptics.Haptics
import com.tt.honeyDue.ui.theme.*
import com.tt.honeyDue.viewmodel.ContractorViewModel
import org.jetbrains.compose.resources.stringResource
@@ -383,6 +384,7 @@ fun CompleteTaskScreen(
OrganicPrimaryButton(
text = stringResource(Res.string.completions_complete_button),
onClick = {
Haptics.success() // P5 Stream S — task completion haptic
isSubmitting = true
val notesWithContractor = buildString {
selectedContractor?.let {