You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
3.5 KiB
145 lines
3.5 KiB
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import '../controllers/agent_controller.dart';
|
|
|
|
/// 声音柱动画组件
|
|
/// 用于显示语音输入时的音频波形效果
|
|
class SoundBarWidget extends StatefulWidget {
|
|
final double delay;
|
|
final bool isActive;
|
|
|
|
const SoundBarWidget({
|
|
Key? key,
|
|
required this.delay,
|
|
required this.isActive,
|
|
}) : super(key: key);
|
|
|
|
@override
|
|
State<SoundBarWidget> createState() => _SoundBarWidgetState();
|
|
}
|
|
|
|
class _SoundBarWidgetState extends State<SoundBarWidget>
|
|
with SingleTickerProviderStateMixin {
|
|
late AnimationController _controller;
|
|
late Animation<double> _animation;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
|
|
_controller = AnimationController(
|
|
vsync: this,
|
|
duration: const Duration(milliseconds: 500),
|
|
);
|
|
|
|
_animation = Tween<double>(begin: 3, end: 18).animate(
|
|
CurvedAnimation(
|
|
parent: _controller,
|
|
curve: Curves.easeInOut,
|
|
),
|
|
)..addListener(() {
|
|
setState(() {});
|
|
});
|
|
|
|
_startOrStopAnimation();
|
|
}
|
|
|
|
@override
|
|
void didUpdateWidget(SoundBarWidget oldWidget) {
|
|
super.didUpdateWidget(oldWidget);
|
|
if (widget.isActive != oldWidget.isActive) {
|
|
_startOrStopAnimation();
|
|
}
|
|
}
|
|
|
|
/// 开始或停止动画
|
|
void _startOrStopAnimation() {
|
|
if (widget.isActive) {
|
|
Future.delayed(Duration(milliseconds: (widget.delay * 1000).toInt()), () {
|
|
if (mounted && widget.isActive) {
|
|
_controller.repeat(reverse: true);
|
|
}
|
|
});
|
|
} else {
|
|
_controller.reset();
|
|
// 设置为小高度的静态状态
|
|
_controller.animateTo(0.1, duration: const Duration(milliseconds: 300));
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_controller.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final primaryColor = Theme.of(context).primaryColor;
|
|
|
|
return Container(
|
|
width: 2.5,
|
|
height: widget.isActive ? _animation.value : 3,
|
|
margin: const EdgeInsets.symmetric(horizontal: 1),
|
|
decoration: BoxDecoration(
|
|
color: widget.isActive
|
|
? primaryColor.withOpacity(0.8)
|
|
: Colors.grey.withOpacity(0.4),
|
|
borderRadius: BorderRadius.circular(1.5),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 声音柱组合组件
|
|
/// 包含多个声音柱的组合显示
|
|
class SoundBarsWidget extends StatelessWidget {
|
|
final bool isActive;
|
|
final int barCount;
|
|
|
|
const SoundBarsWidget({
|
|
Key? key,
|
|
required this.isActive,
|
|
this.barCount = 10,
|
|
}) : super(key: key);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Row(
|
|
mainAxisAlignment: MainAxisAlignment.start,
|
|
children: List.generate(barCount, (index) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 1),
|
|
child: SoundBarWidget(
|
|
delay: index * 0.1,
|
|
isActive: isActive,
|
|
),
|
|
);
|
|
}),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 带控制器集成的声音柱组件
|
|
/// 自动从AgentController获取状态
|
|
class AgentSoundBarsWidget extends StatelessWidget {
|
|
final int barCount;
|
|
|
|
const AgentSoundBarsWidget({
|
|
Key? key,
|
|
this.barCount = 10,
|
|
}) : super(key: key);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Obx(() {
|
|
final controller = Get.find<AgentController>();
|
|
final shouldShowAnimation =
|
|
controller.isListening.value || controller.isPushToTalkActive.value;
|
|
return SoundBarsWidget(
|
|
isActive: shouldShowAnimation,
|
|
barCount: barCount,
|
|
);
|
|
});
|
|
}
|
|
}
|
|
|