10 changed files with 1323 additions and 831 deletions
@ -1,11 +1,11 @@ |
|||||
import 'package:get/get.dart'; |
import 'package:get/get.dart'; |
||||
import '../controllers/agent_controller.dart'; |
import '../controllers/agent_controller.dart'; |
||||
import '../controllers/report_controller.dart'; |
import '../controllers/message_action_controller.dart'; |
||||
|
|
||||
class AgentBinding extends Bindings { |
class AgentBinding extends Bindings { |
||||
@override |
@override |
||||
void dependencies() { |
void dependencies() { |
||||
Get.lazyPut<AgentController>(() => AgentController()); |
Get.lazyPut<AgentController>(() => AgentController()); |
||||
Get.lazyPut<ReportController>(() => ReportController()); |
Get.lazyPut<MessageActionController>(() => MessageActionController()); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,402 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter/services.dart'; |
||||
|
import 'package:get/get.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
import 'package:haptic_feedback/haptic_feedback.dart'; |
||||
|
import '../../../core/theme/app_colors.dart'; |
||||
|
import '../../../data/models/message_model.dart'; |
||||
|
import '../../../data/services/network/api.dart'; |
||||
|
|
||||
|
/// 消息操作控制器 |
||||
|
/// 负责处理消息长按、复制、举报等操作 |
||||
|
class MessageActionController extends GetxController { |
||||
|
// 当前举报的消息 |
||||
|
final reportingMessage = Rxn<Message>(); |
||||
|
|
||||
|
// 选择的举报原因 |
||||
|
List<String> selectedReasons = []; |
||||
|
|
||||
|
// 举报描述 |
||||
|
final reportDescription = ''.obs; |
||||
|
|
||||
|
/// 处理消息长按事件 |
||||
|
void onLongPressMessage( |
||||
|
BuildContext context, |
||||
|
bool isDarkMode, |
||||
|
LongPressStartDetails details, |
||||
|
Message message, |
||||
|
) { |
||||
|
// 触发触觉反馈 |
||||
|
Haptics.vibrate(HapticsType.success); |
||||
|
|
||||
|
// 计算弹出菜单位置 |
||||
|
RenderBox? renderBox = Overlay.of(context).context.findRenderObject() as RenderBox; |
||||
|
final RelativeRect position = RelativeRect.fromRect( |
||||
|
Rect.fromLTRB( |
||||
|
details.globalPosition.dx, |
||||
|
details.globalPosition.dy, |
||||
|
details.globalPosition.dx + 110, // 菜单显示位置X轴坐标 |
||||
|
details.globalPosition.dy - 40, // 菜单显示位置Y轴坐标 |
||||
|
), |
||||
|
Offset.zero & renderBox.size, |
||||
|
); |
||||
|
|
||||
|
// 显示弹出菜单 |
||||
|
showMenu( |
||||
|
context: context, |
||||
|
position: position, |
||||
|
color: isDarkMode ? AppColors.cardBackground : Colors.white, |
||||
|
shape: RoundedRectangleBorder( |
||||
|
borderRadius: BorderRadius.circular(12.r), |
||||
|
), |
||||
|
items: _buildMenuItems(context, isDarkMode, message), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
/// 构建弹出菜单项 |
||||
|
List<PopupMenuEntry> _buildMenuItems( |
||||
|
BuildContext context, |
||||
|
bool isDarkMode, |
||||
|
Message message, |
||||
|
) { |
||||
|
final List<PopupMenuEntry> items = [ |
||||
|
// 复制选项 |
||||
|
_buildPopupMenuItem( |
||||
|
Icon( |
||||
|
Icons.copy, |
||||
|
size: 20.w, |
||||
|
color: isDarkMode ? Colors.white : Colors.black87, |
||||
|
), |
||||
|
'复制', |
||||
|
isDarkMode ? Colors.white : Colors.black87, |
||||
|
() => _copyMessage(message), |
||||
|
), |
||||
|
]; |
||||
|
|
||||
|
// 如果不是用户消息,添加举报选项 |
||||
|
if (!message.isUser) { |
||||
|
items.addAll([ |
||||
|
// 分隔线 |
||||
|
PopupMenuItem( |
||||
|
height: 1, |
||||
|
enabled: false, |
||||
|
child: Divider( |
||||
|
height: 1, |
||||
|
thickness: 0.8, |
||||
|
indent: 0, |
||||
|
endIndent: 0, |
||||
|
color: isDarkMode ? Colors.grey[700] : Colors.grey[300], |
||||
|
), |
||||
|
), |
||||
|
// 举报选项 |
||||
|
_buildPopupMenuItem( |
||||
|
Icon( |
||||
|
Icons.report, |
||||
|
size: 20.w, |
||||
|
color: isDarkMode ? Colors.red[700] : Colors.red, |
||||
|
), |
||||
|
'举报'.tr, |
||||
|
isDarkMode ? Colors.red[700]! : Colors.red, |
||||
|
() => _showReportForm(context, isDarkMode, message), |
||||
|
), |
||||
|
]); |
||||
|
} |
||||
|
|
||||
|
return items; |
||||
|
} |
||||
|
|
||||
|
/// 构建弹出菜单项 |
||||
|
PopupMenuEntry _buildPopupMenuItem( |
||||
|
Icon icon, |
||||
|
String title, |
||||
|
Color color, |
||||
|
Function() onTap, |
||||
|
) { |
||||
|
return PopupMenuItem( |
||||
|
onTap: onTap, |
||||
|
child: SizedBox( |
||||
|
width: 140.w, |
||||
|
child: Row( |
||||
|
children: [ |
||||
|
icon, |
||||
|
8.horizontalSpace, |
||||
|
Text( |
||||
|
title, |
||||
|
style: TextStyle( |
||||
|
color: color, |
||||
|
fontSize: 14.sp, |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
/// 复制消息内容 |
||||
|
void _copyMessage(Message message) { |
||||
|
Clipboard.setData(ClipboardData(text: message.text)).then((_) { |
||||
|
Get.snackbar( |
||||
|
'success'.tr, |
||||
|
'复制成功', |
||||
|
backgroundColor: Colors.blue.withOpacity(0.8), |
||||
|
colorText: Colors.white, |
||||
|
); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/// 显示举报表单 |
||||
|
void _showReportForm(BuildContext context, bool isDarkMode, Message message) { |
||||
|
// 初始化举报状态 |
||||
|
initReport(message); |
||||
|
|
||||
|
showModalBottomSheet( |
||||
|
context: context, |
||||
|
isScrollControlled: true, |
||||
|
backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white, |
||||
|
shape: RoundedRectangleBorder( |
||||
|
borderRadius: BorderRadius.vertical(top: Radius.circular(16.r)), |
||||
|
), |
||||
|
builder: (BuildContext context) { |
||||
|
return Padding( |
||||
|
padding: EdgeInsets.only( |
||||
|
bottom: MediaQuery.of(context).viewInsets.bottom, |
||||
|
), |
||||
|
child: _ReportForm(isDarkMode: isDarkMode), |
||||
|
); |
||||
|
}, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
/// 初始化举报状态 |
||||
|
void initReport(Message message) { |
||||
|
reportingMessage.value = message; |
||||
|
selectedReasons.clear(); |
||||
|
reportDescription.value = ''; |
||||
|
} |
||||
|
|
||||
|
/// 切换举报原因选择状态 |
||||
|
void toggleReason(String reason) { |
||||
|
if (selectedReasons.contains(reason)) { |
||||
|
selectedReasons.remove(reason); |
||||
|
} else { |
||||
|
selectedReasons.add(reason); |
||||
|
} |
||||
|
update(); |
||||
|
} |
||||
|
|
||||
|
/// 更新举报描述 |
||||
|
void updateDescription(String text) { |
||||
|
reportDescription.value = text; |
||||
|
} |
||||
|
|
||||
|
/// 提交举报 |
||||
|
Future<void> submitReport() async { |
||||
|
if (reportingMessage.value == null) return; |
||||
|
|
||||
|
// 构建举报数据 |
||||
|
final reportData = { |
||||
|
'describe': reportDescription.value, |
||||
|
'message': [], |
||||
|
'reportContext': reportingMessage.value!.text, |
||||
|
'reporttype': selectedReasons.toString(), |
||||
|
}; |
||||
|
|
||||
|
try { |
||||
|
// 调用API提交举报 |
||||
|
var response = await Api.reportAiContent(reportData); |
||||
|
|
||||
|
if (response != null) { |
||||
|
print('提交举报响应: $response'); |
||||
|
} |
||||
|
|
||||
|
// 提交成功后重置状态 |
||||
|
selectedReasons.clear(); |
||||
|
reportDescription.value = ''; |
||||
|
reportingMessage.value = null; |
||||
|
|
||||
|
// 关闭举报表单 |
||||
|
Navigator.of(Get.context!).pop(); |
||||
|
|
||||
|
// 显示成功通知 |
||||
|
Get.snackbar( |
||||
|
'提交成功', |
||||
|
'举报已提交,我们会尽快处理', |
||||
|
backgroundColor: Colors.green.withOpacity(0.8), |
||||
|
colorText: Colors.white, |
||||
|
duration: const Duration(seconds: 2), |
||||
|
); |
||||
|
} catch (e) { |
||||
|
// 显示错误通知 |
||||
|
Get.snackbar( |
||||
|
'提交失败', |
||||
|
'网络错误,请稍后重试', |
||||
|
backgroundColor: Colors.red.withOpacity(0.8), |
||||
|
colorText: Colors.white, |
||||
|
duration: const Duration(seconds: 2), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// 举报表单组件 |
||||
|
class _ReportForm extends StatelessWidget { |
||||
|
final bool isDarkMode; |
||||
|
final MessageActionController controller = Get.find<MessageActionController>(); |
||||
|
|
||||
|
_ReportForm({required this.isDarkMode}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Container( |
||||
|
padding: EdgeInsets.all(16.w), |
||||
|
child: SingleChildScrollView( |
||||
|
child: GetBuilder<MessageActionController>( |
||||
|
builder: (_) => Column( |
||||
|
mainAxisSize: MainAxisSize.min, |
||||
|
crossAxisAlignment: CrossAxisAlignment.stretch, |
||||
|
children: [ |
||||
|
// 标题栏 |
||||
|
Stack( |
||||
|
alignment: Alignment.center, |
||||
|
children: [ |
||||
|
Center( |
||||
|
child: Text( |
||||
|
'举报', |
||||
|
style: TextStyle( |
||||
|
fontSize: 18.sp, |
||||
|
fontWeight: FontWeight.bold, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
Positioned( |
||||
|
right: 0, |
||||
|
child: IconButton( |
||||
|
icon: Icon( |
||||
|
Icons.close, |
||||
|
color: isDarkMode ? Colors.grey[400] : Colors.black54, |
||||
|
), |
||||
|
onPressed: () => Navigator.pop(context), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
|
||||
|
// 分隔线 |
||||
|
Container( |
||||
|
padding: EdgeInsets.symmetric(horizontal: 12.w), |
||||
|
margin: EdgeInsets.only(bottom: 10.w), |
||||
|
child: Divider( |
||||
|
height: 1, |
||||
|
color: Colors.grey[300], |
||||
|
), |
||||
|
), |
||||
|
|
||||
|
// 举报原因选择 |
||||
|
GetBuilder<MessageActionController>( |
||||
|
builder: (controller) { |
||||
|
return Wrap( |
||||
|
spacing: 8.w, |
||||
|
runSpacing: 8.h, |
||||
|
children: [ |
||||
|
_buildReportChip('有害/不安全', isDarkMode, controller), |
||||
|
_buildReportChip('色情低俗', isDarkMode, controller), |
||||
|
_buildReportChip('误导攻击', isDarkMode, controller), |
||||
|
_buildReportChip('违法犯罪', isDarkMode, controller), |
||||
|
_buildReportChip('隐私相关', isDarkMode, controller), |
||||
|
_buildReportChip('侵犯我的著作权、名誉权等', isDarkMode, controller), |
||||
|
_buildReportChip('其他', isDarkMode, controller), |
||||
|
], |
||||
|
); |
||||
|
}, |
||||
|
), |
||||
|
|
||||
|
SizedBox(height: 16.h), |
||||
|
|
||||
|
// 描述输入框 |
||||
|
Container( |
||||
|
padding: EdgeInsets.all(12.w), |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode ? Colors.grey[800] : Colors.grey[200], |
||||
|
borderRadius: BorderRadius.circular(8.r), |
||||
|
), |
||||
|
child: TextField( |
||||
|
maxLines: 3, |
||||
|
onChanged: controller.updateDescription, |
||||
|
style: TextStyle( |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
), |
||||
|
decoration: InputDecoration( |
||||
|
hintText: '我们想知道你举报的原因,你可以描述你遇到的问题。', |
||||
|
hintStyle: TextStyle( |
||||
|
color: isDarkMode ? Colors.white70 : Colors.black54, |
||||
|
fontSize: 14.sp, |
||||
|
), |
||||
|
border: InputBorder.none, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
|
||||
|
SizedBox(height: 14.h), |
||||
|
|
||||
|
// 提交按钮 |
||||
|
ElevatedButton( |
||||
|
style: ElevatedButton.styleFrom( |
||||
|
backgroundColor: Colors.blue, |
||||
|
foregroundColor: Colors.white, |
||||
|
padding: EdgeInsets.symmetric(vertical: 12.h), |
||||
|
shape: RoundedRectangleBorder( |
||||
|
borderRadius: BorderRadius.circular(8.r), |
||||
|
), |
||||
|
), |
||||
|
child: Text('提交'), |
||||
|
onPressed: () => controller.submitReport(), |
||||
|
), |
||||
|
|
||||
|
SizedBox(height: 8.h), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
/// 构建举报原因芯片 |
||||
|
Widget _buildReportChip( |
||||
|
String label, |
||||
|
bool isDarkMode, |
||||
|
MessageActionController controller, |
||||
|
) { |
||||
|
final isSelected = controller.selectedReasons.contains(label); |
||||
|
|
||||
|
return GestureDetector( |
||||
|
onTap: () => controller.toggleReason(label), |
||||
|
child: Container( |
||||
|
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h), |
||||
|
decoration: BoxDecoration( |
||||
|
color: isSelected |
||||
|
? Colors.red |
||||
|
: (isDarkMode ? Colors.grey[800] : Colors.grey[200]), |
||||
|
borderRadius: BorderRadius.circular(16.r), |
||||
|
border: Border.all( |
||||
|
color: isSelected |
||||
|
? Colors.red[700]! |
||||
|
: (isDarkMode ? Colors.grey[700]! : Colors.grey[300]!), |
||||
|
width: isSelected ? 1.0 : 0.5, |
||||
|
), |
||||
|
), |
||||
|
child: Text( |
||||
|
label, |
||||
|
style: TextStyle( |
||||
|
color: isSelected |
||||
|
? Colors.white |
||||
|
: (isDarkMode ? Colors.white : Colors.black87), |
||||
|
fontSize: 14.sp, |
||||
|
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -1,80 +0,0 @@ |
|||||
import 'package:get/get.dart'; |
|
||||
//import 'agent_controller.dart'; // 确保导入Message模型 |
|
||||
import 'package:flutter/material.dart'; |
|
||||
import '../../../data/services/network/api.dart'; |
|
||||
import '../../../data/models/message_model.dart'; |
|
||||
|
|
||||
class ReportController extends GetxController { |
|
||||
// 当前举报的消息 |
|
||||
final reportingMessage = Rxn<Message>(); |
|
||||
|
|
||||
// 选择的举报原因 |
|
||||
List<String> selectedReasons = []; |
|
||||
|
|
||||
// 举报描述 |
|
||||
final reportDescription = ''.obs; |
|
||||
|
|
||||
// 初始化举报状态 |
|
||||
void initReport(Message message) { |
|
||||
reportingMessage.value = message; |
|
||||
selectedReasons.clear(); |
|
||||
reportDescription.value = ''; |
|
||||
} |
|
||||
|
|
||||
// 切换举报原因选择状态 |
|
||||
void toggleReason(String reason) { |
|
||||
if (selectedReasons.contains(reason)) { |
|
||||
selectedReasons.remove(reason); |
|
||||
} else { |
|
||||
selectedReasons.add(reason); |
|
||||
} |
|
||||
update(); |
|
||||
} |
|
||||
|
|
||||
// 更新举报描述 |
|
||||
void updateDescription(String text) { |
|
||||
reportDescription.value = text; |
|
||||
} |
|
||||
|
|
||||
// 提交举报 |
|
||||
Future<void> submitReport() async { |
|
||||
if (reportingMessage.value == null) return; |
|
||||
|
|
||||
// 构建举报数据 |
|
||||
final reportData = { |
|
||||
'describe': reportDescription.value, |
|
||||
// 将Message对象转换为可序列化的Map |
|
||||
'message': [], |
|
||||
// 同样处理reportContext |
|
||||
'reportContext': reportingMessage.value!.text, |
|
||||
|
|
||||
'reporttype': selectedReasons.toString(), |
|
||||
}; |
|
||||
|
|
||||
print('提交举报数据: ${reportData}'); |
|
||||
|
|
||||
//调用API提交举报: |
|
||||
var response = await Api.reportAiContent(reportData); |
|
||||
|
|
||||
if (response != null) { |
|
||||
print('提交举报响应: $response'); |
|
||||
} |
|
||||
|
|
||||
// 提交成功后重置状态 |
|
||||
selectedReasons.clear(); |
|
||||
reportDescription.value = ''; |
|
||||
reportingMessage.value = null; |
|
||||
|
|
||||
// 关闭举报表单 |
|
||||
Navigator.of(Get.context!).pop(); |
|
||||
|
|
||||
// 显示成功通知 |
|
||||
Get.snackbar( |
|
||||
'提交成功', |
|
||||
'举报已提交,我们会尽快处理', |
|
||||
backgroundColor: Colors.green.withOpacity(0.8), |
|
||||
colorText: Colors.white, |
|
||||
duration: const Duration(seconds: 2), |
|
||||
); |
|
||||
} |
|
||||
} |
|
||||
File diff suppressed because it is too large
@ -0,0 +1,143 @@ |
|||||
|
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>(); |
||||
|
return SoundBarsWidget( |
||||
|
isActive: controller.isListening.value, |
||||
|
barCount: barCount, |
||||
|
); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue