|
|
|
@ -20,229 +20,259 @@ class SpeechTab extends GetView<MeetingDetailsController> { |
|
|
|
return Stack( |
|
|
|
children: [ |
|
|
|
Obx( |
|
|
|
() => ListView.builder( |
|
|
|
itemCount: controller.textList.length, |
|
|
|
padding: EdgeInsets.only(bottom: 80.w), |
|
|
|
itemBuilder: (BuildContext context, int index) { |
|
|
|
Map item = controller.textList[index]; |
|
|
|
TextStyle textStyle = TextStyle( |
|
|
|
fontSize: 15.sp, |
|
|
|
color: MeetingUIUtils.getTextColor(isDarkMode), |
|
|
|
letterSpacing: 0, |
|
|
|
height: 1.4, |
|
|
|
); |
|
|
|
return Column( |
|
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
|
children: [ |
|
|
|
Padding( |
|
|
|
padding: EdgeInsets.only(top: 10.w), |
|
|
|
child: Row( |
|
|
|
() => controller.meetingDetails.value.tasktype != 10002 |
|
|
|
? ListView.builder( |
|
|
|
itemCount: controller.textList.length, |
|
|
|
padding: EdgeInsets.only(bottom: 80.w), |
|
|
|
itemBuilder: (BuildContext context, int index) { |
|
|
|
Map item = controller.textList[index]; |
|
|
|
TextStyle textStyle = TextStyle( |
|
|
|
fontSize: 15.sp, |
|
|
|
color: MeetingUIUtils.getTextColor(isDarkMode), |
|
|
|
letterSpacing: 0, |
|
|
|
height: 1.4, |
|
|
|
); |
|
|
|
return Column( |
|
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
|
children: [ |
|
|
|
if (item['speaker'].isNotEmpty) |
|
|
|
Container( |
|
|
|
width: 11.w, |
|
|
|
height: 11.w, |
|
|
|
margin: EdgeInsets.only(right: 3.w), |
|
|
|
decoration: BoxDecoration( |
|
|
|
borderRadius: BorderRadius.circular(11.r), |
|
|
|
border: Border.all( |
|
|
|
color: const Color(0xFFFFC107), |
|
|
|
width: 3.w, |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
if (item['speaker'].isNotEmpty) |
|
|
|
GestureDetector( |
|
|
|
onTap: () { |
|
|
|
if (controller.isSpeakerText.value) return; |
|
|
|
Get.bottomSheet( |
|
|
|
SpeakerBottomSheet(item['id'], item['speaker']), |
|
|
|
isScrollControlled: true, |
|
|
|
backgroundColor: isDarkMode ? Colors.grey[800] : Colors.grey[100], |
|
|
|
shape: RoundedRectangleBorder( |
|
|
|
borderRadius: BorderRadius.vertical( |
|
|
|
top: Radius.circular(12.r), |
|
|
|
Padding( |
|
|
|
padding: EdgeInsets.only(top: 10.w), |
|
|
|
child: Row( |
|
|
|
children: [ |
|
|
|
if (item['speaker'].isNotEmpty) |
|
|
|
Container( |
|
|
|
width: 11.w, |
|
|
|
height: 11.w, |
|
|
|
margin: EdgeInsets.only(right: 3.w), |
|
|
|
decoration: BoxDecoration( |
|
|
|
borderRadius: BorderRadius.circular(11.r), |
|
|
|
border: Border.all( |
|
|
|
color: const Color(0xFFFFC107), |
|
|
|
width: 3.w, |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
); |
|
|
|
}, |
|
|
|
child: Padding( |
|
|
|
padding: EdgeInsets.only(right: 5.w), |
|
|
|
child: Text( |
|
|
|
item['speaker'], |
|
|
|
if (item['speaker'].isNotEmpty) |
|
|
|
GestureDetector( |
|
|
|
onTap: () { |
|
|
|
if (controller.isSpeakerText.value) return; |
|
|
|
Get.bottomSheet( |
|
|
|
SpeakerBottomSheet( |
|
|
|
item['id'], item['speaker']), |
|
|
|
isScrollControlled: true, |
|
|
|
backgroundColor: isDarkMode |
|
|
|
? Colors.grey[800] |
|
|
|
: Colors.grey[100], |
|
|
|
shape: RoundedRectangleBorder( |
|
|
|
borderRadius: BorderRadius.vertical( |
|
|
|
top: Radius.circular(12.r), |
|
|
|
), |
|
|
|
), |
|
|
|
); |
|
|
|
}, |
|
|
|
child: Padding( |
|
|
|
padding: EdgeInsets.only(right: 5.w), |
|
|
|
child: Text( |
|
|
|
item['speaker'], |
|
|
|
style: TextStyle( |
|
|
|
color: const Color(0xFFFFC107), |
|
|
|
fontSize: 13.sp, |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
Text( |
|
|
|
DateUtil.formatDateMs( |
|
|
|
item['starttime'], |
|
|
|
format: 'HH:mm:ss', |
|
|
|
isUtc: true, |
|
|
|
), |
|
|
|
style: TextStyle( |
|
|
|
color: const Color(0xFFFFC107), |
|
|
|
color: MeetingUIUtils.getSecondaryTextColor( |
|
|
|
isDarkMode), |
|
|
|
fontSize: 13.sp, |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
Text( |
|
|
|
DateUtil.formatDateMs( |
|
|
|
item['starttime'], |
|
|
|
format: 'HH:mm:ss', |
|
|
|
isUtc: true, |
|
|
|
), |
|
|
|
style: TextStyle( |
|
|
|
color: MeetingUIUtils.getSecondaryTextColor(isDarkMode), |
|
|
|
fontSize: 13.sp, |
|
|
|
Obx(() { |
|
|
|
bool isActive = false; |
|
|
|
int starttime = item['starttime']; |
|
|
|
int endtime = 0; |
|
|
|
if (index == controller.textList.length - 1) { |
|
|
|
endtime = controller.durationMax.value; |
|
|
|
} else { |
|
|
|
endtime = controller.textList[index + 1] |
|
|
|
['starttime']; |
|
|
|
} |
|
|
|
if (controller.currentDuration.value != 0) { |
|
|
|
if (controller.currentDuration.value >= |
|
|
|
starttime && |
|
|
|
controller.currentDuration.value < |
|
|
|
endtime) { |
|
|
|
isActive = true; |
|
|
|
} |
|
|
|
} |
|
|
|
return isActive |
|
|
|
? Container( |
|
|
|
width: 16.w, |
|
|
|
height: 16.w, |
|
|
|
margin: EdgeInsets.only(left: 5.w), |
|
|
|
alignment: Alignment.center, |
|
|
|
clipBehavior: Clip.hardEdge, |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: Colors.red[100], |
|
|
|
borderRadius: |
|
|
|
BorderRadius.circular(4.r), |
|
|
|
), |
|
|
|
child: Transform.scale( |
|
|
|
scale: 1.6, |
|
|
|
child: Lottie.asset( |
|
|
|
'assets/lottie/sound_effect.json', |
|
|
|
controller: |
|
|
|
controller.lottieController, |
|
|
|
), |
|
|
|
), |
|
|
|
) |
|
|
|
: const SizedBox(); |
|
|
|
}), |
|
|
|
], |
|
|
|
), |
|
|
|
), |
|
|
|
Obx(() { |
|
|
|
bool isActive = false; |
|
|
|
int starttime = item['starttime']; |
|
|
|
int endtime = 0; |
|
|
|
if (index == controller.textList.length - 1) { |
|
|
|
endtime = controller.durationMax.value; |
|
|
|
if (controller.isSpeakerText.value) { |
|
|
|
TextEditingController speakerTextController = |
|
|
|
TextEditingController(text: item['content']); |
|
|
|
return Obx( |
|
|
|
() => Container( |
|
|
|
padding: EdgeInsets.symmetric( |
|
|
|
horizontal: 14.w, |
|
|
|
), |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: controller.editSpeakerTextId.value == |
|
|
|
item['id'] |
|
|
|
? Colors.blue[100] |
|
|
|
: null, |
|
|
|
borderRadius: BorderRadius.circular(8.w), |
|
|
|
), |
|
|
|
child: FocusScope( |
|
|
|
onFocusChange: (bool hasFocus) { |
|
|
|
if (hasFocus) { |
|
|
|
controller.editSpeakerTextId.value = |
|
|
|
item['id']; |
|
|
|
controller.editSpeakerTextChange = ''; |
|
|
|
} else { |
|
|
|
if (speakerTextController.text != |
|
|
|
item['content']) { |
|
|
|
Map? foundElement = controller |
|
|
|
.editSpeakerTextList |
|
|
|
.firstWhere( |
|
|
|
(element) => |
|
|
|
element['id'] == item['id'], |
|
|
|
orElse: () => null, |
|
|
|
); |
|
|
|
if (foundElement != null) { |
|
|
|
foundElement['content'] = |
|
|
|
speakerTextController.text; |
|
|
|
} else { |
|
|
|
controller.editSpeakerTextList.add({ |
|
|
|
'id': item['id'], |
|
|
|
'content': |
|
|
|
speakerTextController.text, |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
child: TextField( |
|
|
|
controller: speakerTextController, |
|
|
|
style: textStyle, |
|
|
|
minLines: 1, |
|
|
|
maxLines: 100, |
|
|
|
decoration: InputDecoration( |
|
|
|
isDense: true, |
|
|
|
fillColor: Colors.transparent, |
|
|
|
border: InputBorder.none, |
|
|
|
contentPadding: |
|
|
|
EdgeInsets.symmetric(vertical: 5.w), |
|
|
|
), |
|
|
|
onChanged: (String value) { |
|
|
|
controller.editSpeakerTextChange = value; |
|
|
|
}, |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
); |
|
|
|
} else { |
|
|
|
endtime = |
|
|
|
controller.textList[index + 1]['starttime']; |
|
|
|
} |
|
|
|
if (controller.currentDuration.value != 0) { |
|
|
|
if (controller.currentDuration.value >= starttime && |
|
|
|
controller.currentDuration.value < endtime) { |
|
|
|
isActive = true; |
|
|
|
} |
|
|
|
} |
|
|
|
return isActive |
|
|
|
? Container( |
|
|
|
width: 16.w, |
|
|
|
height: 16.w, |
|
|
|
margin: EdgeInsets.only(left: 5.w), |
|
|
|
alignment: Alignment.center, |
|
|
|
clipBehavior: Clip.hardEdge, |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: Colors.red[100], |
|
|
|
borderRadius: BorderRadius.circular(4.r), |
|
|
|
return Obx(() { |
|
|
|
bool isActive = false; |
|
|
|
int starttime = item['starttime']; |
|
|
|
int endtime = 0; |
|
|
|
if (index == controller.textList.length - 1) { |
|
|
|
endtime = controller.durationMax.value; |
|
|
|
} else { |
|
|
|
endtime = |
|
|
|
controller.textList[index + 1]['starttime']; |
|
|
|
} |
|
|
|
if (controller.currentDuration.value != 0) { |
|
|
|
if (controller.currentDuration.value >= |
|
|
|
starttime && |
|
|
|
controller.currentDuration.value < |
|
|
|
endtime) { |
|
|
|
isActive = true; |
|
|
|
} |
|
|
|
} |
|
|
|
return GestureDetector( |
|
|
|
behavior: HitTestBehavior.translucent, |
|
|
|
onTap: () { |
|
|
|
if (isActive) { |
|
|
|
if (controller.isPlay.value) { |
|
|
|
controller.playerController.pausePlayer(); |
|
|
|
} else { |
|
|
|
controller.playerController.startPlayer(); |
|
|
|
} |
|
|
|
} else { |
|
|
|
controller.playerController |
|
|
|
.seekTo(item['starttime']); |
|
|
|
controller.playerController.startPlayer(); |
|
|
|
} |
|
|
|
}, |
|
|
|
child: Container( |
|
|
|
width: double.infinity, |
|
|
|
padding: EdgeInsets.symmetric( |
|
|
|
horizontal: 14.w, |
|
|
|
vertical: 5.w, |
|
|
|
), |
|
|
|
child: Transform.scale( |
|
|
|
scale: 1.6, |
|
|
|
child: Lottie.asset( |
|
|
|
'assets/lottie/sound_effect.json', |
|
|
|
controller: controller.lottieController, |
|
|
|
child: Text( |
|
|
|
item['content'], |
|
|
|
style: TextStyle( |
|
|
|
fontSize: 15.sp, |
|
|
|
color: isActive |
|
|
|
? Colors.red |
|
|
|
: MeetingUIUtils.getTextColor( |
|
|
|
isDarkMode), |
|
|
|
letterSpacing: 0, |
|
|
|
height: 1.4, |
|
|
|
), |
|
|
|
), |
|
|
|
) |
|
|
|
: const SizedBox(); |
|
|
|
), |
|
|
|
); |
|
|
|
}); |
|
|
|
} |
|
|
|
}), |
|
|
|
], |
|
|
|
); |
|
|
|
}, |
|
|
|
) |
|
|
|
: Container( |
|
|
|
height: 200.w, |
|
|
|
alignment: Alignment.center, |
|
|
|
child: Text( |
|
|
|
'转写失败,请稍后重试', |
|
|
|
style: TextStyle( |
|
|
|
color: MeetingUIUtils.getSecondaryTextColor(isDarkMode), |
|
|
|
fontSize: 14.sp, |
|
|
|
), |
|
|
|
), |
|
|
|
Obx(() { |
|
|
|
if (controller.isSpeakerText.value) { |
|
|
|
TextEditingController speakerTextController = |
|
|
|
TextEditingController(text: item['content']); |
|
|
|
return Obx( |
|
|
|
() => Container( |
|
|
|
padding: EdgeInsets.symmetric( |
|
|
|
horizontal: 14.w, |
|
|
|
), |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: |
|
|
|
controller.editSpeakerTextId.value == item['id'] |
|
|
|
? Colors.blue[100] |
|
|
|
: null, |
|
|
|
borderRadius: BorderRadius.circular(8.w), |
|
|
|
), |
|
|
|
child: FocusScope( |
|
|
|
onFocusChange: (bool hasFocus) { |
|
|
|
if (hasFocus) { |
|
|
|
controller.editSpeakerTextId.value = item['id']; |
|
|
|
controller.editSpeakerTextChange = ''; |
|
|
|
} else { |
|
|
|
if (speakerTextController.text != |
|
|
|
item['content']) { |
|
|
|
Map? foundElement = |
|
|
|
controller.editSpeakerTextList.firstWhere( |
|
|
|
(element) => element['id'] == item['id'], |
|
|
|
orElse: () => null, |
|
|
|
); |
|
|
|
if (foundElement != null) { |
|
|
|
foundElement['content'] = |
|
|
|
speakerTextController.text; |
|
|
|
} else { |
|
|
|
controller.editSpeakerTextList.add({ |
|
|
|
'id': item['id'], |
|
|
|
'content': speakerTextController.text, |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
child: TextField( |
|
|
|
controller: speakerTextController, |
|
|
|
style: textStyle, |
|
|
|
minLines: 1, |
|
|
|
maxLines: 100, |
|
|
|
decoration: InputDecoration( |
|
|
|
isDense: true, |
|
|
|
fillColor: Colors.transparent, |
|
|
|
border: InputBorder.none, |
|
|
|
contentPadding: |
|
|
|
EdgeInsets.symmetric(vertical: 5.w), |
|
|
|
), |
|
|
|
onChanged: (String value) { |
|
|
|
controller.editSpeakerTextChange = value; |
|
|
|
}, |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
); |
|
|
|
} else { |
|
|
|
return Obx(() { |
|
|
|
bool isActive = false; |
|
|
|
int starttime = item['starttime']; |
|
|
|
int endtime = 0; |
|
|
|
if (index == controller.textList.length - 1) { |
|
|
|
endtime = controller.durationMax.value; |
|
|
|
} else { |
|
|
|
endtime = controller.textList[index + 1]['starttime']; |
|
|
|
} |
|
|
|
if (controller.currentDuration.value != 0) { |
|
|
|
if (controller.currentDuration.value >= starttime && |
|
|
|
controller.currentDuration.value < endtime) { |
|
|
|
isActive = true; |
|
|
|
} |
|
|
|
} |
|
|
|
return GestureDetector( |
|
|
|
behavior: HitTestBehavior.translucent, |
|
|
|
onTap: () { |
|
|
|
if (isActive) { |
|
|
|
if (controller.isPlay.value) { |
|
|
|
controller.playerController.pausePlayer(); |
|
|
|
} else { |
|
|
|
controller.playerController.startPlayer(); |
|
|
|
} |
|
|
|
} else { |
|
|
|
controller.playerController |
|
|
|
.seekTo(item['starttime']); |
|
|
|
controller.playerController.startPlayer(); |
|
|
|
} |
|
|
|
}, |
|
|
|
child: Container( |
|
|
|
width: double.infinity, |
|
|
|
padding: EdgeInsets.symmetric( |
|
|
|
horizontal: 14.w, |
|
|
|
vertical: 5.w, |
|
|
|
), |
|
|
|
child: Text( |
|
|
|
item['content'], |
|
|
|
style: TextStyle( |
|
|
|
fontSize: 15.sp, |
|
|
|
color: isActive ? Colors.red : MeetingUIUtils.getTextColor(isDarkMode), |
|
|
|
letterSpacing: 0, |
|
|
|
height: 1.4, |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
); |
|
|
|
}); |
|
|
|
} |
|
|
|
}), |
|
|
|
], |
|
|
|
); |
|
|
|
}, |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
Obx( |
|
|
|
() => Positioned( |
|
|
|
@ -253,7 +283,8 @@ class SpeechTab extends GetView<MeetingDetailsController> { |
|
|
|
mainAxisAlignment: MainAxisAlignment.center, |
|
|
|
children: [ |
|
|
|
if (controller.meetingDetails.value.tasktype >= 2 && |
|
|
|
!controller.isSpeakerText.value) |
|
|
|
!controller.isSpeakerText.value && |
|
|
|
controller.meetingDetails.value.tasktype != 10002) |
|
|
|
_button( |
|
|
|
Icons.edit, |
|
|
|
'editSpeaker'.tr, // 对应中文:编辑 |
|
|
|
@ -264,7 +295,8 @@ class SpeechTab extends GetView<MeetingDetailsController> { |
|
|
|
}, |
|
|
|
), |
|
|
|
if (controller.meetingDetails.value.tasktype >= 2 && |
|
|
|
!controller.isSpeakerText.value) |
|
|
|
!controller.isSpeakerText.value && |
|
|
|
controller.meetingDetails.value.tasktype != 10002) |
|
|
|
_button( |
|
|
|
Icons.supervisor_account, |
|
|
|
'nameSpeaker'.tr, // 对应中文:命名发言者 |
|
|
|
@ -272,7 +304,8 @@ class SpeechTab extends GetView<MeetingDetailsController> { |
|
|
|
Get.bottomSheet( |
|
|
|
const SpeakerAllBottomSheet(), |
|
|
|
isScrollControlled: true, |
|
|
|
backgroundColor: isDarkMode ? Colors.grey[800] : Colors.grey[100], |
|
|
|
backgroundColor: |
|
|
|
isDarkMode ? Colors.grey[800] : Colors.grey[100], |
|
|
|
shape: RoundedRectangleBorder( |
|
|
|
borderRadius: BorderRadius.vertical( |
|
|
|
top: Radius.circular(12.r), |
|
|
|
@ -282,7 +315,8 @@ class SpeechTab extends GetView<MeetingDetailsController> { |
|
|
|
}, |
|
|
|
), |
|
|
|
if (controller.meetingDetails.value.tasktype >= 2 && |
|
|
|
!controller.isSpeakerText.value) |
|
|
|
!controller.isSpeakerText.value && |
|
|
|
controller.meetingDetails.value.tasktype != 10002) |
|
|
|
_button( |
|
|
|
Icons.auto_awesome, |
|
|
|
'Ask AI', |
|
|
|
@ -290,7 +324,8 @@ class SpeechTab extends GetView<MeetingDetailsController> { |
|
|
|
Get.bottomSheet( |
|
|
|
const AIBottomSheet(), |
|
|
|
isScrollControlled: true, |
|
|
|
backgroundColor: isDarkMode ? Colors.grey[800] : Colors.white, |
|
|
|
backgroundColor: |
|
|
|
isDarkMode ? Colors.grey[800] : Colors.white, |
|
|
|
shape: RoundedRectangleBorder( |
|
|
|
borderRadius: BorderRadius.vertical( |
|
|
|
top: Radius.circular(12.r), |
|
|
|
@ -309,7 +344,29 @@ class SpeechTab extends GetView<MeetingDetailsController> { |
|
|
|
Get.bottomSheet( |
|
|
|
const GenerateBottomSheet(), |
|
|
|
isScrollControlled: true, |
|
|
|
backgroundColor: isDarkMode ? Colors.grey[800] : Colors.grey[100], |
|
|
|
backgroundColor: |
|
|
|
isDarkMode ? Colors.grey[800] : Colors.grey[100], |
|
|
|
shape: RoundedRectangleBorder( |
|
|
|
borderRadius: BorderRadius.vertical( |
|
|
|
top: Radius.circular(12.r), |
|
|
|
), |
|
|
|
), |
|
|
|
); |
|
|
|
}, |
|
|
|
), |
|
|
|
), |
|
|
|
if (controller.meetingDetails.value.tasktype == 10002) |
|
|
|
SizedBox( |
|
|
|
width: 150.w, |
|
|
|
child: _button( |
|
|
|
Icons.auto_awesome, |
|
|
|
'重新生成', |
|
|
|
() { |
|
|
|
Get.bottomSheet( |
|
|
|
const GenerateBottomSheet(), |
|
|
|
isScrollControlled: true, |
|
|
|
backgroundColor: |
|
|
|
isDarkMode ? Colors.grey[800] : Colors.grey[100], |
|
|
|
shape: RoundedRectangleBorder( |
|
|
|
borderRadius: BorderRadius.vertical( |
|
|
|
top: Radius.circular(12.r), |
|
|
|
|