Skip to content

Commit 7b37396

Browse files
committed
Refactor audio recording controls for improved UI and functionality
- Replaced MicOff icon with Square icon in MainRecordingControls and SimplifiedControls for a more intuitive user experience. - Enhanced button interactions to streamline recording start/stop actions, including a pulsing effect during recording. - Updated status messages and button states to provide clearer feedback on recording status and actions. - Improved accessibility by ensuring buttons are disabled appropriately based on recording state and microphone access.
1 parent 7c098c7 commit 7b37396

File tree

2 files changed

+82
-68
lines changed

2 files changed

+82
-68
lines changed
Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Mic, MicOff } from 'lucide-react'
1+
import { Mic, Square } from 'lucide-react'
22
import { UseAudioRecordingReturn } from '../../hooks/useAudioRecording'
33

44
interface MainRecordingControlsProps {
@@ -11,45 +11,50 @@ export default function MainRecordingControls({ recording }: MainRecordingContro
1111
return (
1212
<div className="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 p-6 mb-6">
1313
<div className="text-center">
14-
<div className="mb-6">
15-
{recording.isRecording ? (
16-
<button
17-
onClick={recording.stopRecording}
18-
className="w-20 h-20 bg-red-600 hover:bg-red-700 text-white rounded-full flex items-center justify-center transition-colors shadow-lg"
19-
>
20-
<MicOff className="h-8 w-8" />
21-
</button>
22-
) : (
23-
<button
24-
onClick={recording.startRecording}
25-
disabled={!recording.canAccessMicrophone || recording.connectionStatus === 'connecting'}
26-
className="w-20 h-20 bg-blue-600 hover:bg-blue-700 text-white rounded-full flex items-center justify-center transition-colors shadow-lg disabled:opacity-50 disabled:cursor-not-allowed"
27-
>
28-
<Mic className="h-8 w-8" />
29-
</button>
30-
)}
14+
<div className="mb-6 flex justify-center">
15+
<div className="relative">
16+
{recording.isRecording && (
17+
<span className="absolute inset-0 rounded-full bg-red-400 opacity-30 animate-ping" />
18+
)}
19+
{recording.isRecording ? (
20+
<button
21+
onClick={recording.stopRecording}
22+
className="relative w-20 h-20 bg-red-600 hover:bg-red-700 text-white rounded-full flex items-center justify-center transition-colors shadow-lg"
23+
>
24+
<Square className="h-8 w-8 fill-current" />
25+
</button>
26+
) : (
27+
<button
28+
onClick={recording.startRecording}
29+
disabled={!recording.canAccessMicrophone || recording.connectionStatus === 'connecting'}
30+
className="relative w-20 h-20 bg-blue-600 hover:bg-blue-700 text-white rounded-full flex items-center justify-center transition-colors shadow-lg disabled:opacity-50 disabled:cursor-not-allowed"
31+
>
32+
<Mic className="h-8 w-8" />
33+
</button>
34+
)}
35+
</div>
3136
</div>
3237

3338
<div className="space-y-2">
3439
<p className="text-lg font-semibold text-gray-900 dark:text-gray-100">
3540
{recording.isRecording ? 'Recording...' : 'Ready to Record'}
3641
</p>
37-
42+
3843
{recording.isRecording && (
39-
<p className="text-2xl font-mono text-blue-600 dark:text-blue-400">
44+
<p className="text-2xl font-mono text-red-600 dark:text-red-400">
4045
{recording.formatDuration(recording.recordingDuration)}
4146
</p>
4247
)}
43-
48+
4449
<p className="text-sm text-gray-600 dark:text-gray-400">
45-
{recording.isRecording
46-
? `Audio streaming via ${isHttps ? 'WSS (secure)' : 'WS'} to backend for processing`
47-
: recording.canAccessMicrophone
48-
? 'Click the microphone to start recording'
50+
{recording.isRecording
51+
? `Click to stop \u00b7 Streaming via ${isHttps ? 'WSS (secure)' : 'WS'}`
52+
: recording.canAccessMicrophone
53+
? 'Click to start recording'
4954
: 'Secure connection required for microphone access'}
5055
</p>
5156
</div>
5257
</div>
5358
</div>
5459
)
55-
}
60+
}
Lines changed: 51 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Mic, MicOff, Loader2 } from 'lucide-react'
1+
import { Mic, Square, Loader2 } from 'lucide-react'
22
import { RecordingContextType } from '../../contexts/RecordingContext'
33

44
interface SimplifiedControlsProps {
@@ -18,73 +18,82 @@ const getStepText = (step: string): string => {
1818
}
1919
}
2020

21-
const getButtonColor = (step: string, isRecording: boolean): string => {
22-
if (step === 'error') return 'bg-red-600 hover:bg-red-700'
23-
if (isRecording) return 'bg-red-600 hover:bg-red-700'
24-
if (step === 'idle') return 'bg-blue-600 hover:bg-blue-700'
25-
return 'bg-yellow-600 hover:bg-yellow-700'
26-
}
27-
2821
const isProcessing = (step: string): boolean => {
2922
return ['mic', 'websocket', 'audio-start', 'streaming', 'stopping'].includes(step)
3023
}
3124

3225
export default function SimplifiedControls({ recording }: SimplifiedControlsProps) {
33-
const startButtonDisabled = !recording.canAccessMicrophone || isProcessing(recording.currentStep) || recording.isRecording
34-
26+
const processing = isProcessing(recording.currentStep)
27+
const canStart = recording.canAccessMicrophone && !processing && !recording.isRecording
28+
29+
const handleClick = () => {
30+
if (recording.isRecording) {
31+
recording.stopRecording()
32+
} else if (canStart) {
33+
recording.startRecording()
34+
}
35+
}
36+
37+
// Button appearance based on state
38+
const getButtonClasses = (): string => {
39+
if (recording.isRecording) return 'bg-red-600 hover:bg-red-700'
40+
if (processing) return 'bg-yellow-600'
41+
if (recording.currentStep === 'error') return 'bg-red-600 hover:bg-red-700'
42+
return 'bg-blue-600 hover:bg-blue-700'
43+
}
44+
45+
const isDisabled = recording.isRecording ? false : (processing || !canStart)
46+
3547
return (
3648
<div className="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 p-8 mb-6">
3749
<div className="text-center">
38-
{/* Control Buttons */}
39-
<div className="mb-6 flex justify-center space-x-4">
40-
{/* START Button */}
41-
<button
42-
onClick={recording.startRecording}
43-
disabled={startButtonDisabled}
44-
className={`w-24 h-24 ${recording.isRecording || isProcessing(recording.currentStep) ? 'bg-gray-400' : getButtonColor(recording.currentStep, recording.isRecording)} text-white rounded-full flex items-center justify-center transition-all duration-200 shadow-lg disabled:opacity-50 disabled:cursor-not-allowed transform hover:scale-105 active:scale-95`}
45-
>
46-
{isProcessing(recording.currentStep) ? (
47-
<Loader2 className="h-10 w-10 animate-spin" />
48-
) : (
49-
<Mic className="h-10 w-10" />
50+
{/* Single Toggle Button */}
51+
<div className="mb-6 flex justify-center">
52+
<div className="relative">
53+
{/* Pulsing ring when recording */}
54+
{recording.isRecording && (
55+
<span className="absolute inset-0 rounded-full bg-red-400 opacity-30 animate-ping" />
5056
)}
51-
</button>
52-
53-
{/* STOP Button - only show when recording */}
54-
{recording.isRecording && (
5557
<button
56-
onClick={recording.stopRecording}
57-
className="w-24 h-24 bg-red-600 hover:bg-red-700 text-white rounded-full flex items-center justify-center transition-all duration-200 shadow-lg transform hover:scale-105 active:scale-95"
58+
onClick={handleClick}
59+
disabled={isDisabled}
60+
className={`relative w-24 h-24 ${getButtonClasses()} text-white rounded-full flex items-center justify-center transition-all duration-200 shadow-lg disabled:opacity-50 disabled:cursor-not-allowed transform hover:scale-105 active:scale-95`}
5861
>
59-
<MicOff className="h-10 w-10" />
62+
{recording.isRecording ? (
63+
<Square className="h-10 w-10 fill-current" />
64+
) : processing ? (
65+
<Loader2 className="h-10 w-10 animate-spin" />
66+
) : (
67+
<Mic className="h-10 w-10" />
68+
)}
6069
</button>
61-
)}
70+
</div>
6271
</div>
63-
72+
6473
{/* Status Text */}
6574
<div className="space-y-2">
6675
<h2 className="text-xl font-semibold text-gray-900 dark:text-gray-100">
6776
{recording.isRecording ? 'Recording in Progress' : getStepText(recording.currentStep)}
6877
</h2>
69-
78+
7079
{/* Recording Duration */}
7180
{recording.isRecording && (
72-
<p className="text-3xl font-mono text-blue-600 dark:text-blue-400">
81+
<p className="text-3xl font-mono text-red-600 dark:text-red-400">
7382
{recording.formatDuration(recording.recordingDuration)}
7483
</p>
7584
)}
76-
85+
7786
{/* Action Text */}
7887
<p className="text-sm text-gray-600 dark:text-gray-400">
79-
{recording.isRecording
80-
? 'Click the red STOP button to end recording'
81-
: recording.currentStep === 'idle'
82-
? 'Click the blue START button to begin recording'
88+
{recording.isRecording
89+
? 'Click to stop recording'
90+
: recording.currentStep === 'idle'
91+
? 'Click to start recording'
8392
: recording.currentStep === 'error'
84-
? 'Click START to try again'
93+
? 'Click to try again'
8594
: 'Please wait while setting up...'}
8695
</p>
87-
96+
8897
{/* Error Message */}
8998
{recording.error && (
9099
<div className="mt-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg">
@@ -93,7 +102,7 @@ export default function SimplifiedControls({ recording }: SimplifiedControlsProp
93102
</p>
94103
</div>
95104
)}
96-
105+
97106
{/* Security Warning */}
98107
{!recording.canAccessMicrophone && (
99108
<div className="mt-4 p-3 bg-orange-50 dark:bg-orange-900/20 border border-orange-200 dark:border-orange-800 rounded-lg">
@@ -106,4 +115,4 @@ export default function SimplifiedControls({ recording }: SimplifiedControlsProp
106115
</div>
107116
</div>
108117
)
109-
}
118+
}

0 commit comments

Comments
 (0)