feat(dictation): add resilient rpc retries and status toasts

This commit is contained in:
Mohamed Boudra
2025-12-02 08:12:02 +00:00
parent 71b238c0cd
commit dc26bf713e
8 changed files with 1213 additions and 111 deletions
@@ -1,8 +1,9 @@
import { View, Text, Pressable, ActivityIndicator } from "react-native";
import { StyleSheet, useUnistyles } from "react-native-unistyles";
import { X, ArrowUp } from "lucide-react-native";
import { X, ArrowUp, RefreshCcw } from "lucide-react-native";
import { VolumeMeter } from "./volume-meter";
import { FOOTER_HEIGHT } from "@/contexts/footer-controls-context";
import type { DictationStatus } from "@/hooks/use-dictation";
interface VoiceNoteRecordingOverlayProps {
volume: number;
@@ -10,6 +11,9 @@ interface VoiceNoteRecordingOverlayProps {
onCancel: () => void;
onSend: () => void;
isTranscribing?: boolean;
status?: DictationStatus;
onRetry?: () => void;
onDiscardFailed?: () => void;
}
function formatDuration(seconds: number): string {
@@ -24,13 +28,25 @@ export function VoiceNoteRecordingOverlay({
onCancel,
onSend,
isTranscribing = false,
status = "idle",
onRetry,
onDiscardFailed,
}: VoiceNoteRecordingOverlayProps) {
const { theme } = useUnistyles();
const isRetrying = status === "retrying";
const isFailed = status === "failed";
const primaryDisabled = isTranscribing || isRetrying;
const handlePrimary = isFailed ? onRetry ?? onSend : onSend;
const handleCancel = isFailed && onDiscardFailed ? onDiscardFailed : onCancel;
return (
<View style={[styles.container, { backgroundColor: theme.colors.palette.blue[600] }]}>
{/* Cancel button */}
<Pressable onPress={onCancel} disabled={isTranscribing} style={[styles.cancelButton, isTranscribing && styles.buttonDisabled]}>
<Pressable
onPress={handleCancel}
disabled={isTranscribing}
style={[styles.cancelButton, isTranscribing && styles.buttonDisabled]}
>
<X size={24} color={theme.colors.palette.white} strokeWidth={2.5} />
</Pressable>
@@ -49,9 +65,17 @@ export function VoiceNoteRecordingOverlay({
</View>
{/* Send button */}
<Pressable onPress={onSend} disabled={isTranscribing} style={[styles.sendButton, { backgroundColor: theme.colors.palette.white }]}>
{isTranscribing ? (
<Pressable
onPress={handlePrimary}
disabled={primaryDisabled}
style={[styles.sendButton, { backgroundColor: theme.colors.palette.white }, primaryDisabled && styles.buttonDisabled]}
>
{isRetrying ? (
<ActivityIndicator size="small" color={theme.colors.palette.blue[600]} />
) : isTranscribing ? (
<ActivityIndicator size="small" color={theme.colors.palette.blue[600]} />
) : isFailed ? (
<RefreshCcw size={24} color={theme.colors.palette.blue[600]} strokeWidth={2.5} />
) : (
<ArrowUp size={24} color={theme.colors.palette.blue[600]} strokeWidth={2.5} />
)}