Browse Source

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

newdev_shunjiawei
lxm 1 year ago
parent
commit
efd1c0df64
  1. 35
      lib/modules/meeting/controllers/meeting_details_controller.dart
  2. 297
      lib/modules/meeting/views/meeting_details_view.dart
  3. 10
      lib/modules/meeting/views/mind_map_tab.dart

35
lib/modules/meeting/controllers/meeting_details_controller.dart

@ -4,6 +4,7 @@ import 'dart:convert';
import 'package:audio_waveforms/audio_waveforms.dart'; import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart'; import 'package:get_storage/get_storage.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
@ -18,13 +19,13 @@ import '../model/meeting_model.dart';
class MeetingDetailsController extends GetxController class MeetingDetailsController extends GetxController
with GetSingleTickerProviderStateMixin { with GetSingleTickerProviderStateMixin {
late ScrollController scrollController;
late TabController tabController; late TabController tabController;
final RxInt currentIndex = 0.obs; final RxInt currentIndex = 0.obs;
final PlayerController playerController = PlayerController(); final PlayerController playerController = PlayerController();
RxBool isTop = false.obs; RxBool isTop = false.obs;
RxInt durationMax = 0.obs; RxInt durationMax = 0.obs;
RxDouble dragOffset = 210.0.w.obs;
int id = 0; int id = 0;
@ -52,8 +53,6 @@ class MeetingDetailsController extends GetxController
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
scrollController = ScrollController(initialScrollOffset: 0.0);
scrollController.addListener(_onScroll);
tabController = TabController(length: 4, vsync: this); tabController = TabController(length: 4, vsync: this);
tabController.addListener(() { tabController.addListener(() {
currentIndex.value = tabController.index; currentIndex.value = tabController.index;
@ -70,38 +69,12 @@ class MeetingDetailsController extends GetxController
@override @override
void onClose() { void onClose() {
scrollController.dispose();
tabController.dispose(); tabController.dispose();
playerController.dispose(); playerController.dispose();
_isDisposed = true; _isDisposed = true;
super.onClose(); super.onClose();
} }
void _onScroll() async {
double pixels = scrollController.position.pixels;
double maxScrollExtent = scrollController.position.maxScrollExtent;
if (!isTop.value && pixels > 5) {
await scrollController.animateTo(
maxScrollExtent,
duration: const Duration(milliseconds: 100),
curve: Curves.easeOut,
);
if (pixels > maxScrollExtent - 2) {
isTop.value = true;
}
}
if (isTop.value && pixels < maxScrollExtent - 5) {
await scrollController.animateTo(
0,
duration: const Duration(milliseconds: 100),
curve: Curves.easeOut,
);
if (pixels < 2) {
isTop.value = false;
}
}
}
void _getAgent() async { void _getAgent() async {
final GetStorage storage = GetStorage(); final GetStorage storage = GetStorage();
Map userInfo = storage.read("user_info"); Map userInfo = storage.read("user_info");
@ -113,6 +86,10 @@ class MeetingDetailsController extends GetxController
final data = await SqfliteApi.getMeetingDetails(id); final data = await SqfliteApi.getMeetingDetails(id);
meetingData.value = MeetingModel.fromJson(data); meetingData.value = MeetingModel.fromJson(data);
meetingDetails.value = MeetingDetailsModel.fromJson(data['details']); meetingDetails.value = MeetingDetailsModel.fromJson(data['details']);
if (meetingDetails.value.summary.isNotEmpty) {
dragOffset.value = 0;
isTop.value = true;
}
await playerController.preparePlayer( await playerController.preparePlayer(
path: meetingData.value.filepath, path: meetingData.value.filepath,
noOfSamples: 1200, noOfSamples: 1200,

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

@ -161,21 +161,63 @@ class MeetingDetailsView extends GetView<MeetingDetailsController> {
// 构建主体内容 // 构建主体内容
Widget _buildBody(BuildContext context, bool isDarkMode) { Widget _buildBody(BuildContext context, bool isDarkMode) {
double initialPosition = 0;
return Column( return Column(
children: [ children: [
_soundWave(isDarkMode), GestureDetector(
Container( behavior: HitTestBehavior.translucent,
padding: EdgeInsets.symmetric(horizontal: 8.w), onVerticalDragStart: (DragStartDetails dragStartDetails) {
margin: EdgeInsets.symmetric(vertical: 10.w), initialPosition = dragStartDetails.localPosition.dy;
child: Obx( },
() => Row( onVerticalDragUpdate: (DragUpdateDetails dragUpdateDetails) {
children: [ controller.dragOffset.value += dragUpdateDetails.delta.dy;
_iconItem(Icons.summarize, '概述', 0), },
_iconItem(Icons.message, '转写', 1), onVerticalDragEnd: (DragEndDetails dragEndDetails) {
_iconItem(Icons.article, '总结', 2), double offset = initialPosition - dragEndDetails.localPosition.dy;
_iconItem(Icons.lan, '思维导图', 3), if (offset > 0) {
], if (controller.isTop.value) {
), controller.dragOffset.value = 0;
return;
}
if (offset > 60) {
controller.dragOffset.value = 0;
controller.isTop.value = true;
} else {
controller.dragOffset.value = 210.w;
controller.isTop.value = false;
}
} else {
if (!controller.isTop.value) {
controller.dragOffset.value = 210.w;
return;
}
if (offset < -60) {
controller.dragOffset.value = 210.w;
controller.isTop.value = false;
} else {
controller.dragOffset.value = 0;
controller.isTop.value = true;
}
}
},
child: Column(
children: [
_soundWave(isDarkMode),
Container(
padding: EdgeInsets.symmetric(horizontal: 8.w),
margin: EdgeInsets.symmetric(vertical: 10.w),
child: Obx(
() => Row(
children: [
_iconItem(Icons.summarize, '概述', 0),
_iconItem(Icons.message, '转写', 1),
_iconItem(Icons.article, '总结', 2),
_iconItem(Icons.lan, '思维导图', 3),
],
),
),
),
],
), ),
), ),
Expanded( Expanded(
@ -184,11 +226,15 @@ class MeetingDetailsView extends GetView<MeetingDetailsController> {
child: TabBarView( child: TabBarView(
controller: controller.tabController, controller: controller.tabController,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
children: const [ children: [
OverviewTab(), const OverviewTab(),
SpeechTab(), const SpeechTab(),
SummaryTab(), const SummaryTab(),
MindMapTab(), Obx(
() => controller.meetingDetails.value.summary.isNotEmpty
? const MindMapTab()
: const SizedBox(),
),
], ],
), ),
), ),
@ -198,108 +244,131 @@ class MeetingDetailsView extends GetView<MeetingDetailsController> {
} }
Widget _soundWave(bool isDarkMode) { Widget _soundWave(bool isDarkMode) {
return Container( return Obx(
height: 200.w, () => SizedBox(
margin: EdgeInsets.only(bottom: 10.w), height: controller.dragOffset.value < 0
decoration: BoxDecoration( ? 0
color: Colors.grey[200]!, : controller.dragOffset.value > 210.w
borderRadius: BorderRadius.vertical( ? 210.w
bottom: Radius.circular(20.r), : controller.dragOffset.value,
), child: Stack(
), children: [
child: Column( Positioned(
children: [ bottom: 0,
Container( child: Container(
margin: EdgeInsets.only(bottom: 5.w), width: 1.sw,
decoration: BoxDecoration( height: 200.w,
color: Colors.white, margin: EdgeInsets.only(bottom: 10.w),
borderRadius: BorderRadius.circular(8.r), decoration: BoxDecoration(
), color: Colors.grey[200]!,
child: AudioFileWaveforms( borderRadius: BorderRadius.vertical(
size: Size(350.w, 120.w), bottom: Radius.circular(20.r),
playerController: controller.playerController, ),
playerWaveStyle: PlayerWaveStyle( ),
fixedWaveColor: Colors.grey[300]!, child: Column(
liveWaveColor: Colors.red, children: [
seekLineColor: Colors.red, Container(
scaleFactor: 600, margin: EdgeInsets.only(bottom: 5.w),
), decoration: BoxDecoration(
), color: Colors.white,
), borderRadius: BorderRadius.circular(8.r),
SizedBox(
width: 350.w,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
StreamBuilder<int>(
stream: controller.playerController.onCurrentDurationChanged,
builder: (context, snapshot) {
final position = snapshot.data ?? 0;
return Text(
DateUtil.formatDateMs(
position,
format: 'HH:mm:ss',
isUtc: true,
), ),
style: TextStyle( child: AudioFileWaveforms(
color: isDarkMode ? Colors.grey[400] : Colors.grey[500], size: Size(350.w, 120.w),
fontSize: 12.sp, playerController: controller.playerController,
playerWaveStyle: PlayerWaveStyle(
fixedWaveColor: Colors.grey[300]!,
liveWaveColor: Colors.red,
seekLineColor: Colors.red,
scaleFactor: 600,
),
), ),
);
},
),
Obx(
() => Text(
DateUtil.formatDateMs(
controller.durationMax.value,
format: 'HH:mm:ss',
isUtc: true,
), ),
style: TextStyle( SizedBox(
color: isDarkMode ? Colors.grey[400] : Colors.grey[500], width: 350.w,
fontSize: 12.sp, child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
StreamBuilder<int>(
stream: controller
.playerController.onCurrentDurationChanged,
builder: (context, snapshot) {
final position = snapshot.data ?? 0;
return Text(
DateUtil.formatDateMs(
position,
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: [
), Icon(
), Icons.replay_10,
Row( color: Colors.black,
mainAxisAlignment: MainAxisAlignment.spaceEvenly, size: 30.w,
children: [ ),
Icon( StreamBuilder<PlayerState>(
Icons.replay_10, stream:
color: Colors.black, controller.playerController.onPlayerStateChanged,
size: 30.w, builder: (context, snapshot) {
), bool isPlay = snapshot.data?.isPlaying ?? false;
StreamBuilder<PlayerState>( return GestureDetector(
stream: controller.playerController.onPlayerStateChanged, onTap: () {
builder: (context, snapshot) { if (isPlay) {
bool isPlay = snapshot.data?.isPlaying ?? false; controller.playerController.pausePlayer();
return GestureDetector( } else {
onTap: () { controller.playerController.startPlayer();
if (isPlay) { }
controller.playerController.pausePlayer(); },
} else { child: Icon(
controller.playerController.startPlayer(); isPlay ? Icons.pause_circle : Icons.play_circle,
} color: Colors.black,
}, size: 48.w,
child: Icon( ),
isPlay ? Icons.pause_circle : Icons.play_circle, );
color: Colors.black, },
size: 48.w, ),
Icon(
Icons.forward_10,
color: Colors.black,
size: 30.w,
),
],
), ),
); ],
}, ),
),
Icon(
Icons.forward_10,
color: Colors.black,
size: 30.w,
), ),
], ),
), ],
], ),
), ),
); );
} }

10
lib/modules/meeting/views/mind_map_tab.dart

@ -11,7 +11,8 @@ class MindMapTab extends StatefulWidget {
State<MindMapTab> createState() => _MindMapTabState(); State<MindMapTab> createState() => _MindMapTabState();
} }
class _MindMapTabState extends State<MindMapTab> { class _MindMapTabState extends State<MindMapTab>
with AutomaticKeepAliveClientMixin {
late final WebViewController _controller; late final WebViewController _controller;
final _meetingDetailsController = Get.find<MeetingDetailsController>(); final _meetingDetailsController = Get.find<MeetingDetailsController>();
@ -41,12 +42,14 @@ class _MindMapTabState extends State<MindMapTab> {
height: 100%; height: 100%;
margin: 0; margin: 0;
padding: 0; padding: 0;
overflow: hidden;
} }
.markmap { .markmap {
width: 100%; width: 100%;
height: 100%; height: 100%;
position: relative; position: relative;
overflow: hidden;
} }
.markmap>svg { .markmap>svg {
@ -76,6 +79,7 @@ class _MindMapTabState extends State<MindMapTab> {
markmap: markmap:
maxWidth: 300 maxWidth: 300
colorFreezeLevel: 2 colorFreezeLevel: 2
initialExpandLevel: 3
--- ---
${_meetingDetailsController.meetingDetails.value.summary} ${_meetingDetailsController.meetingDetails.value.summary}
</script> </script>
@ -90,8 +94,12 @@ ${_meetingDetailsController.meetingDetails.value.summary}
..loadHtmlString(html); ..loadHtmlString(html);
} }
@override
bool get wantKeepAlive => true;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context);
return WebViewWidget( return WebViewWidget(
controller: _controller, controller: _controller,
); );

Loading…
Cancel
Save