Browse Source

Merge branch 'new_dev' of https://github.com/deepcloud2048/deep_voice into new_dev

newdev_shunjiawei
lxm 1 year ago
parent
commit
b5a3ee7f26
  1. 4
      lib/modules/meeting/controllers/meeting_record_controller.dart
  2. 477
      lib/modules/meeting/views/meeting_details_view.dart
  3. 28
      lib/modules/meeting/views/tabs/summary_tab.dart
  4. 6
      pubspec.yaml

4
lib/modules/meeting/controllers/meeting_record_controller.dart

@ -138,7 +138,7 @@ class MeetingRecordController extends GetxController
switch (audioType.value) {
case 0:
fileName.value = "现场录音";
_audioSourceType = false;
_audioSourceType = true;
break;
case 1:
fileName.value = "音、视频录音";
@ -271,7 +271,7 @@ class MeetingRecordController extends GetxController
void _startHardwareServices() {
switch (audioType.value) {
case 0:
// _bleManager.openEncoder();
_bleManager.openEncoder();
break;
case 1:
_bleManager.openDecoder();

477
lib/modules/meeting/views/meeting_details_view.dart

@ -67,98 +67,102 @@ class MeetingDetailsView extends GetView<MeetingDetailsController> {
),
onPressed: () => Get.back(),
),
title: Opacity(
opacity: controller.isTop.value ? 1.0 : 0.0,
child: Container(
width: 170.w,
padding: EdgeInsets.symmetric(horizontal: 2.w, vertical: 3.w),
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(30.r),
),
child: Row(
children: [
GestureDetector(
onTap: () {
if (controller.meetingData.value.filepath.isEmpty) {
controller.downloadAudio();
} else {
if (controller.isPlay.value) {
controller.playerController.pausePlayer();
title: Obx(
() => Opacity(
opacity: (1 - (controller.dragOffset.value / 100.w)).clamp(0.0, 1.0),
child: Container(
width: 170.w,
padding: EdgeInsets.symmetric(horizontal: 2.w, vertical: 3.w),
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(30.r),
),
child: Row(
children: [
GestureDetector(
onTap: () {
if (controller.meetingData.value.filepath.isEmpty) {
controller.downloadAudio();
} else {
controller.playerController.startPlayer();
if (controller.isPlay.value) {
controller.playerController.pausePlayer();
} else {
controller.playerController.startPlayer();
}
}
}
},
child: Obx(
() => !controller.isLoading.value &&
controller.meetingData.value.filepath.isEmpty
? Obx(
() => Stack(
alignment: Alignment.center,
children: [
if (controller.isDownload.value)
SizedBox(
width: 26.w,
height: 26.w,
child: CircularProgressIndicator(
value: controller.downloadProgress.value,
valueColor:
const AlwaysStoppedAnimation<Color>(
Colors.red),
strokeWidth: 2.w,
},
child: Obx(
() => !controller.isLoading.value &&
controller.meetingData.value.filepath.isEmpty
? Obx(
() => Stack(
alignment: Alignment.center,
children: [
if (controller.isDownload.value)
SizedBox(
width: 26.w,
height: 26.w,
child: CircularProgressIndicator(
value: controller.downloadProgress.value,
valueColor:
const AlwaysStoppedAnimation<Color>(
Colors.red),
strokeWidth: 2.w,
),
),
Icon(
Icons.download_for_offline,
color: Colors.black,
size: 30.w,
),
Icon(
Icons.download_for_offline,
color: Colors.black,
size: 30.w,
),
],
],
),
)
: Icon(
controller.isPlay.value
? Icons.pause_circle
: Icons.play_circle,
color: Colors.black,
size: 30.w,
),
)
: Icon(
controller.isPlay.value
? Icons.pause_circle
: Icons.play_circle,
color: Colors.black,
size: 30.w,
),
),
),
),
4.horizontalSpace,
GestureDetector(
onTap: () {
if (controller.isSpeakerText.value) return;
controller.dragOffset.value = 210.w;
controller.isTop.value = false;
},
child: SizedBox(
width: 130.w,
child: FittedBox(
fit: BoxFit.scaleDown,
child: AudioFileWaveforms(
size: Size(350.w, 30.w),
playerController: controller.playerController,
waveformData: List.generate(88, (int index) {
return 0.01 + Random().nextDouble() * 0.09;
}),
waveformType: WaveformType.fitWidth,
enableSeekGesture: false,
playerWaveStyle: PlayerWaveStyle(
spacing: 4.w,
waveThickness: 2.w,
fixedWaveColor: Colors.grey[400]!,
liveWaveColor: Colors.red,
seekLineColor: Colors.red,
scaleFactor: 200,
4.horizontalSpace,
GestureDetector(
onTap: () {
if (controller.isSpeakerText.value) return;
controller.dragOffset.value = 210.w;
controller.isTop.value = false;
},
behavior: HitTestBehavior.translucent,
child: SizedBox(
width: 130.w,
height: 30.w,
child: FittedBox(
fit: BoxFit.scaleDown,
child: AudioFileWaveforms(
size: Size(350.w, 30.w),
playerController: controller.playerController,
waveformData: List.generate(88, (int index) {
return 0.01 + Random().nextDouble() * 0.09;
}),
waveformType: WaveformType.fitWidth,
enableSeekGesture: false,
playerWaveStyle: PlayerWaveStyle(
spacing: 4.w,
waveThickness: 2.w,
fixedWaveColor: Colors.grey[400]!,
liveWaveColor: Colors.red,
seekLineColor: Colors.red,
scaleFactor: 200,
),
),
),
),
),
),
],
],
),
),
),
),
@ -308,6 +312,7 @@ class MeetingDetailsView extends GetView<MeetingDetailsController> {
child: TabBarView(
controller: controller.tabController,
physics: const NeverScrollableScrollPhysics(),
clipBehavior: Clip.none,
children: [
Obx(
() => controller.isLoading.value
@ -373,176 +378,180 @@ class MeetingDetailsView extends GetView<MeetingDetailsController> {
Widget _soundWave(bool isDarkMode) {
return Obx(
() => SizedBox(
height: controller.dragOffset.value < 0
? 0
: controller.dragOffset.value > 210.w
? 210.w
: controller.dragOffset.value,
child: Stack(
children: [
Positioned(
bottom: 0,
child: Container(
width: 1.sw,
height: 200.w,
margin: EdgeInsets.only(bottom: 10.w),
decoration: BoxDecoration(
color: Colors.grey[200]!,
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(20.r),
() => Opacity(
opacity: (controller.dragOffset.value / 210.w).clamp(0.0, 1.0),
child: SizedBox(
height: controller.dragOffset.value < 0
? 0
: controller.dragOffset.value > 210.w
? 210.w
: controller.dragOffset.value,
child: Stack(
children: [
Positioned(
bottom: 0,
child: Container(
width: 1.sw,
height: 200.w,
margin: EdgeInsets.only(bottom: 10.w),
decoration: BoxDecoration(
color: Colors.grey[200]!,
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(20.r),
),
),
),
child: Column(
children: [
Container(
margin: EdgeInsets.only(bottom: 5.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.r),
),
child: AudioFileWaveforms(
size: Size(350.w, 120.w),
playerController: controller.playerController,
waveformData: List.generate(88, (int index) {
return 0.01 + Random().nextDouble() * 0.09;
}),
waveformType: WaveformType.fitWidth,
playerWaveStyle: PlayerWaveStyle(
spacing: 4.w,
waveThickness: 2.w,
fixedWaveColor: Colors.grey[300]!,
liveWaveColor: Colors.red,
seekLineColor: Colors.red,
scaleFactor: 600,
child: Column(
children: [
Container(
margin: EdgeInsets.only(bottom: 5.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.r),
),
child: AudioFileWaveforms(
size: Size(350.w, 120.w),
playerController: controller.playerController,
waveformData: List.generate(88, (int index) {
return 0.01 + Random().nextDouble() * 0.09;
}),
waveformType: WaveformType.fitWidth,
playerWaveStyle: PlayerWaveStyle(
spacing: 4.w,
waveThickness: 2.w,
fixedWaveColor: Colors.grey[300]!,
liveWaveColor: Colors.red,
seekLineColor: Colors.red,
scaleFactor: 600,
),
),
),
),
SizedBox(
width: 350.w,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Obx(
() => Text(
DateUtil.formatDateMs(
controller.currentDuration.value,
format: 'HH:mm:ss',
isUtc: true,
),
style: TextStyle(
color: isDarkMode
? Colors.grey[400]
: Colors.grey[500],
fontSize: 12.sp,
SizedBox(
width: 350.w,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Obx(
() => Text(
DateUtil.formatDateMs(
controller.currentDuration.value,
format: 'HH:mm:ss',
isUtc: true,
),
style: TextStyle(
color: isDarkMode
? Colors.grey[400]
: Colors.grey[500],
fontSize: 12.sp,
),
),
),
),
Obx(
() => Text(
DateUtil.formatDateMs(
controller.durationMax.value,
format: 'HH:mm:ss',
isUtc: true,
),
style: TextStyle(
color: isDarkMode
? Colors.grey[400]
: Colors.grey[500],
fontSize: 12.sp,
Obx(
() => Text(
DateUtil.formatDateMs(
controller.durationMax.value,
format: 'HH:mm:ss',
isUtc: true,
),
style: TextStyle(
color: isDarkMode
? Colors.grey[400]
: Colors.grey[500],
fontSize: 12.sp,
),
),
),
),
],
],
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: () {
int progress =
controller.currentDuration.value - 10000;
if (progress < 0) {
progress = 0;
}
controller.playerController.seekTo(progress);
},
child: Icon(
Icons.replay_10,
color: Colors.black,
size: 30.w,
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: () {
int progress =
controller.currentDuration.value - 10000;
if (progress < 0) {
progress = 0;
}
controller.playerController.seekTo(progress);
},
child: Icon(
Icons.replay_10,
color: Colors.black,
size: 30.w,
),
),
),
GestureDetector(
onTap: () {
if (controller.meetingData.value.filepath.isEmpty) {
controller.downloadAudio();
} else {
if (controller.isPlay.value) {
controller.playerController.pausePlayer();
GestureDetector(
onTap: () {
if (controller
.meetingData.value.filepath.isEmpty) {
controller.downloadAudio();
} else {
controller.playerController.startPlayer();
if (controller.isPlay.value) {
controller.playerController.pausePlayer();
} else {
controller.playerController.startPlayer();
}
}
}
},
child: Obx(
() => !controller.isLoading.value &&
controller
.meetingData.value.filepath.isEmpty
? Obx(
() => Stack(
alignment: Alignment.center,
children: [
if (controller.isDownload.value)
SizedBox(
width: 42.w,
height: 42.w,
child: CircularProgressIndicator(
value: controller
.downloadProgress.value,
valueColor:
const AlwaysStoppedAnimation<
Color>(Colors.red),
strokeWidth: 3.w,
},
child: Obx(
() => !controller.isLoading.value &&
controller
.meetingData.value.filepath.isEmpty
? Obx(
() => Stack(
alignment: Alignment.center,
children: [
if (controller.isDownload.value)
SizedBox(
width: 42.w,
height: 42.w,
child: CircularProgressIndicator(
value: controller
.downloadProgress.value,
valueColor:
const AlwaysStoppedAnimation<
Color>(Colors.red),
strokeWidth: 3.w,
),
),
Icon(
Icons.download_for_offline,
color: Colors.black,
size: 48.w,
),
Icon(
Icons.download_for_offline,
color: Colors.black,
size: 48.w,
),
],
],
),
)
: Icon(
controller.isPlay.value
? Icons.pause_circle
: Icons.play_circle,
color: Colors.black,
size: 48.w,
),
)
: Icon(
controller.isPlay.value
? Icons.pause_circle
: Icons.play_circle,
color: Colors.black,
size: 48.w,
),
),
),
),
GestureDetector(
onTap: () {
int progress =
controller.currentDuration.value + 10000;
controller.playerController.seekTo(progress);
},
child: Icon(
Icons.forward_10,
color: Colors.black,
size: 30.w,
GestureDetector(
onTap: () {
int progress =
controller.currentDuration.value + 10000;
controller.playerController.seekTo(progress);
},
child: Icon(
Icons.forward_10,
color: Colors.black,
size: 30.w,
),
),
),
],
),
],
],
),
],
),
),
),
),
],
],
),
),
),
);

28
lib/modules/meeting/views/tabs/summary_tab.dart

@ -1,8 +1,10 @@
import 'package:common_utils/common_utils.dart';
import 'package:fleather/fleather.dart';
import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:parchment/codecs.dart';
import '../../../../data/services/db/sqflite_api.dart';
import '../../controllers/meeting_details_controller.dart';
@ -26,6 +28,10 @@ class _SummaryTabState extends State<SummaryTab> {
final TextEditingController _addressController = TextEditingController();
final TextEditingController _personnelController = TextEditingController();
final FocusNode _focusNode = FocusNode();
final GlobalKey<EditorState> _editorKey = GlobalKey();
FleatherController? _fleatherController;
@override
void initState() {
super.initState();
@ -39,6 +45,7 @@ class _SummaryTabState extends State<SummaryTab> {
: '[输入与会人员]');
_addressController.addListener(_handleAddressChanged);
_personnelController.addListener(_handlePersonnelChanged);
_initController();
}
void _handleAddressChanged() {
@ -101,6 +108,12 @@ class _SummaryTabState extends State<SummaryTab> {
}
}
Future<void> _initController() async {
final markdown = const ParchmentMarkdownCodec()
.decode(_controller.meetingDetails.value.summary);
_fleatherController = FleatherController(document: markdown);
}
@override
void dispose() {
_addressController.dispose();
@ -119,6 +132,7 @@ class _SummaryTabState extends State<SummaryTab> {
);
return Stack(
clipBehavior: Clip.none,
children: [
SingleChildScrollView(
padding: EdgeInsets.only(bottom: 80.w),
@ -352,6 +366,20 @@ class _SummaryTabState extends State<SummaryTab> {
),
),
),
Positioned(
bottom: 0,
left: -12.w,
right: -12.w,
child: Container(
height: 40,
color: Colors.white,
alignment: Alignment.center,
child: FleatherToolbar.basic(
controller: _fleatherController!,
editorKey: _editorKey,
),
),
),
],
);
}

6
pubspec.yaml

@ -23,10 +23,8 @@ dependencies:
audio_session: ^0.1.18
flutter_markdown: ^0.7.7+1
markdown: ^7.1.1
appflowy_editor:
git:
url: https://github.com/AppFlowy-IO/appflowy-editor.git
ref: main
fleather: ^1.24.0+1
parchment: ^1.24.0
wifi_iot: ^0.3.19+2
permission_handler: ^10.4.5
web_socket_channel: ^2.4.0

Loading…
Cancel
Save