Update RecordingButton design with new visual style

Major design changes based on user requirements:

1. Background Style Changes:
   - Remove solid color background and shadows
   - Use semi-transparent background (alpha: 0.12) for subtle visual feedback
   - Maintain circular shape for both states

2. Icon Improvements:
   - Increase icon size to 55% of button size for better visibility
   - Use color-coded icons: blue for idle, red for recording
   - Remove white icon color, use theme-based colors instead

3. Loading Indicator Enhancement:
   - Show CircularProgressIndicator during both processing and listening states
   - Position indicator as overlay using Stack layout
   - Maintain white color for progress indicator for contrast

4. Color Logic Simplification:
   - Consolidate color logic into single iconColor variable
   - Remove complex state-based color transitions
   - Use consistent color scheme: blue (#2196F3) idle, red (#FF5252) recording
   - Darker disabled color (#212121) for better contrast

5. Layout Structure Update:
   - Replace Transform.scale animation wrapper with direct Container
   - Use Stack for layering icon and progress indicator
   - Positioned widgets for precise control over element placement

This creates a more modern, minimalist design with better visual hierarchy
and improved accessibility through higher contrast ratios.
This commit is contained in:
Max 2025-09-09 15:08:35 +08:00
parent ac234d99ec
commit aba8b44ab8
1 changed files with 43 additions and 42 deletions

View File

@ -169,7 +169,8 @@ class _RecordingButtonState extends State<RecordingButton>
await _speechService.stopListening(); await _speechService.stopListening();
} else { } else {
await _speechService.startListening( await _speechService.startListening(
partialResults: widget.partialResults); partialResults: widget.partialResults,
);
} }
} catch (e) { } catch (e) {
widget.onError?.call(SpeechRecognitionError( widget.onError?.call(SpeechRecognitionError(
@ -191,60 +192,60 @@ class _RecordingButtonState extends State<RecordingButton>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Color buttonColor; Color iconColor;
if (!widget.enabled || !_isInitialized) { if (!widget.enabled || !_isInitialized) {
buttonColor = widget.disabledColor ?? Colors.grey[400]!; iconColor = widget.disabledColor ?? Colors.grey[850]!;
} else if (_isProcessing) {
buttonColor = _isListening
? (widget.recordingColor ?? const Color(0xFFFF5252))
.withValues(alpha: 0.7)
: (widget.idleColor ?? const Color(0xFF2196F3))
.withValues(alpha: 0.7);
} else if (_isListening) {
buttonColor = widget.recordingColor ?? const Color(0xFFFF5252); //
} else { } else {
buttonColor = widget.idleColor ?? const Color(0xFF2196F3); // iconColor = _isListening
? (widget.recordingColor ?? const Color(0xFFFF5252))
: (widget.idleColor ?? const Color(0xFF2196F3));
} }
Widget button = AnimatedBuilder( Widget button = AnimatedBuilder(
animation: _scaleAnimation, animation: _scaleAnimation,
builder: (context, child) { builder: (context, child) {
return Transform.scale( return Container(
scale: _scaleAnimation.value, width: widget.size,
child: Container( height: widget.size,
width: widget.size, decoration: BoxDecoration(
height: widget.size, color: iconColor.withValues(alpha: 0.12),
decoration: BoxDecoration( shape: BoxShape.circle,
color: buttonColor, ),
shape: BoxShape.circle, child: Material(
boxShadow: [ color: Colors.transparent,
BoxShadow( child: InkWell(
color: buttonColor.withValues(alpha: 0.3), borderRadius: BorderRadius.circular(widget.size / 2),
blurRadius: _isListening ? 20 : 12, onTap: _toggleRecording,
spreadRadius: _isListening ? 5 : 3, child: Stack(
), children: [
], Positioned(
), left: 0,
child: Material( right: 0,
color: Colors.transparent, bottom: 0,
child: InkWell( top: 0,
borderRadius: BorderRadius.circular(widget.size / 2), child: Icon(
onTap: _toggleRecording, _isListening ? Icons.stop_rounded : Icons.mic_rounded,
child: _isProcessing size: widget.size * 0.55,
? SizedBox( color: iconColor,
width: widget.size * 0.4, ),
height: widget.size * 0.4, ),
if (_isProcessing || _isListening)
Positioned(
left: 0,
right: 0,
bottom: 0,
top: 0,
child: SizedBox(
width: widget.size,
height: widget.size,
child: CircularProgressIndicator( child: CircularProgressIndicator(
strokeWidth: 2, strokeWidth: 2,
valueColor: valueColor:
AlwaysStoppedAnimation<Color>(Colors.white), AlwaysStoppedAnimation<Color>(Colors.white),
), ),
)
: Icon(
_isListening ? Icons.stop_rounded : Icons.mic_rounded,
size: widget.size * (_isListening ? 0.35 : 0.4),
color: Colors.white,
), ),
)
],
), ),
), ),
), ),