lxm 1 year ago
parent
commit
17c60f3663
  1. 35
      lib/modules/meeting/controllers/meeting_details_controller.dart
  2. 89
      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:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:http/http.dart' as http;
@ -18,13 +19,13 @@ import '../model/meeting_model.dart';
class MeetingDetailsController extends GetxController
with GetSingleTickerProviderStateMixin {
late ScrollController scrollController;
late TabController tabController;
final RxInt currentIndex = 0.obs;
final PlayerController playerController = PlayerController();
RxBool isTop = false.obs;
RxInt durationMax = 0.obs;
RxDouble dragOffset = 210.0.w.obs;
int id = 0;
@ -52,8 +53,6 @@ class MeetingDetailsController extends GetxController
@override
void onInit() {
super.onInit();
scrollController = ScrollController(initialScrollOffset: 0.0);
scrollController.addListener(_onScroll);
tabController = TabController(length: 4, vsync: this);
tabController.addListener(() {
currentIndex.value = tabController.index;
@ -70,38 +69,12 @@ class MeetingDetailsController extends GetxController
@override
void onClose() {
scrollController.dispose();
tabController.dispose();
playerController.dispose();
_isDisposed = true;
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 {
final GetStorage storage = GetStorage();
Map userInfo = storage.read("user_info");
@ -113,6 +86,10 @@ class MeetingDetailsController extends GetxController
final data = await SqfliteApi.getMeetingDetails(id);
meetingData.value = MeetingModel.fromJson(data);
meetingDetails.value = MeetingDetailsModel.fromJson(data['details']);
if (meetingDetails.value.summary.isNotEmpty) {
dragOffset.value = 0;
isTop.value = true;
}
await playerController.preparePlayer(
path: meetingData.value.filepath,
noOfSamples: 1200,

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

@ -161,7 +161,46 @@ class MeetingDetailsView extends GetView<MeetingDetailsController> {
// 构建主体内容
Widget _buildBody(BuildContext context, bool isDarkMode) {
double initialPosition = 0;
return Column(
children: [
GestureDetector(
behavior: HitTestBehavior.translucent,
onVerticalDragStart: (DragStartDetails dragStartDetails) {
initialPosition = dragStartDetails.localPosition.dy;
},
onVerticalDragUpdate: (DragUpdateDetails dragUpdateDetails) {
controller.dragOffset.value += dragUpdateDetails.delta.dy;
},
onVerticalDragEnd: (DragEndDetails dragEndDetails) {
double offset = initialPosition - dragEndDetails.localPosition.dy;
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(
@ -178,17 +217,24 @@ class MeetingDetailsView extends GetView<MeetingDetailsController> {
),
),
),
],
),
),
Expanded(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 12.w),
child: TabBarView(
controller: controller.tabController,
physics: const NeverScrollableScrollPhysics(),
children: const [
OverviewTab(),
SpeechTab(),
SummaryTab(),
MindMapTab(),
children: [
const OverviewTab(),
const SpeechTab(),
const SummaryTab(),
Obx(
() => controller.meetingDetails.value.summary.isNotEmpty
? const MindMapTab()
: const SizedBox(),
),
],
),
),
@ -198,7 +244,19 @@ class MeetingDetailsView extends GetView<MeetingDetailsController> {
}
Widget _soundWave(bool isDarkMode) {
return Container(
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(
@ -232,7 +290,8 @@ class MeetingDetailsView extends GetView<MeetingDetailsController> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
StreamBuilder<int>(
stream: controller.playerController.onCurrentDurationChanged,
stream: controller
.playerController.onCurrentDurationChanged,
builder: (context, snapshot) {
final position = snapshot.data ?? 0;
return Text(
@ -242,7 +301,9 @@ class MeetingDetailsView extends GetView<MeetingDetailsController> {
isUtc: true,
),
style: TextStyle(
color: isDarkMode ? Colors.grey[400] : Colors.grey[500],
color: isDarkMode
? Colors.grey[400]
: Colors.grey[500],
fontSize: 12.sp,
),
);
@ -256,7 +317,9 @@ class MeetingDetailsView extends GetView<MeetingDetailsController> {
isUtc: true,
),
style: TextStyle(
color: isDarkMode ? Colors.grey[400] : Colors.grey[500],
color: isDarkMode
? Colors.grey[400]
: Colors.grey[500],
fontSize: 12.sp,
),
),
@ -273,7 +336,8 @@ class MeetingDetailsView extends GetView<MeetingDetailsController> {
size: 30.w,
),
StreamBuilder<PlayerState>(
stream: controller.playerController.onPlayerStateChanged,
stream:
controller.playerController.onPlayerStateChanged,
builder: (context, snapshot) {
bool isPlay = snapshot.data?.isPlaying ?? false;
return GestureDetector(
@ -301,6 +365,11 @@ class MeetingDetailsView extends GetView<MeetingDetailsController> {
),
],
),
),
),
],
),
),
);
}

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

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

Loading…
Cancel
Save