liwei1dao 1 year ago
parent
commit
81ff1e7e74
  1. 43
      lib/modules/meeting/controllers/meeting_details_controller.dart
  2. 340
      lib/modules/meeting/views/meeting_details_view.dart
  3. 10
      lib/modules/meeting/views/mind_map_tab.dart
  4. 4
      lib/modules/meeting/views/speaker_all_bottom_sheet.dart
  5. 66
      lib/modules/meeting/views/speech_tab.dart
  6. 212
      lib/modules/meeting/views/summary_tab.dart

43
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,15 @@ 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.w.obs;
RxInt currentDuration = 0.obs;
int id = 0; int id = 0;
@ -52,10 +55,11 @@ 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(() {
if (currentIndex.value == 2 && tabController.index != 2) {
FocusScope.of(Get.context!).unfocus();
}
currentIndex.value = tabController.index; currentIndex.value = tabController.index;
}); });
final Map<String, dynamic> args = Get.arguments ?? {}; final Map<String, dynamic> args = Get.arguments ?? {};
@ -70,38 +74,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,12 +91,19 @@ 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,
); );
durationMax.value = await playerController.getDuration(DurationType.max); durationMax.value = await playerController.getDuration(DurationType.max);
playerController.setFinishMode(finishMode: FinishMode.pause); playerController.setFinishMode(finishMode: FinishMode.pause);
playerController.onCurrentDurationChanged.listen((int position) {
currentDuration.value = position;
});
if (meetingDetails.value.tasktype == 1) { if (meetingDetails.value.tasktype == 1) {
List speakerList = await SqfliteApi.getMeetingSpeaker(id); List speakerList = await SqfliteApi.getMeetingSpeaker(id);
textList.value = List.from(speakerList); textList.value = List.from(speakerList);

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

@ -92,14 +92,22 @@ class MeetingDetailsView extends GetView<MeetingDetailsController> {
}, },
), ),
4.horizontalSpace, 4.horizontalSpace,
AudioFileWaveforms( GestureDetector(
size: Size(130.w, 30.w), onTap: () {
playerController: controller.playerController, if (controller.isSpeakerText.value) return;
playerWaveStyle: PlayerWaveStyle( controller.dragOffset.value = 210.w;
fixedWaveColor: Colors.grey[400]!, controller.isTop.value = false;
liveWaveColor: Colors.red, },
seekLineColor: Colors.red, child: AudioFileWaveforms(
scaleFactor: 100, size: Size(130.w, 30.w),
playerController: controller.playerController,
enableSeekGesture: false,
playerWaveStyle: PlayerWaveStyle(
fixedWaveColor: Colors.grey[400]!,
liveWaveColor: Colors.red,
seekLineColor: Colors.red,
scaleFactor: 100,
),
), ),
), ),
], ],
@ -161,21 +169,67 @@ 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),
Obx(
() => !controller.isSpeakerText.value
? 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),
],
),
),
)
: const SizedBox(),
),
],
), ),
), ),
Expanded( Expanded(
@ -184,11 +238,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 +256,143 @@ 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: [
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,
),
),
),
],
),
), ),
), Row(
), mainAxisAlignment: MainAxisAlignment.spaceEvenly,
], children: [
), GestureDetector(
), onTap: () {
Row( int progress =
mainAxisAlignment: MainAxisAlignment.spaceEvenly, controller.currentDuration.value - 10000;
children: [ if (progress < 0) {
Icon( progress = 0;
Icons.replay_10, }
color: Colors.black, controller.playerController.seekTo(progress);
size: 30.w, },
), child: Icon(
StreamBuilder<PlayerState>( Icons.replay_10,
stream: controller.playerController.onPlayerStateChanged, color: Colors.black,
builder: (context, snapshot) { size: 30.w,
bool isPlay = snapshot.data?.isPlaying ?? false; ),
return GestureDetector( ),
onTap: () { StreamBuilder<PlayerState>(
if (isPlay) { stream:
controller.playerController.pausePlayer(); controller.playerController.onPlayerStateChanged,
} else { builder: (context, snapshot) {
controller.playerController.startPlayer(); bool isPlay = snapshot.data?.isPlaying ?? false;
} return GestureDetector(
}, onTap: () {
child: Icon( if (isPlay) {
isPlay ? Icons.pause_circle : Icons.play_circle, controller.playerController.pausePlayer();
color: Colors.black, } else {
size: 48.w, controller.playerController.startPlayer();
}
},
child: Icon(
isPlay ? 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,
),
),
],
), ),
); ],
}, ),
),
Icon(
Icons.forward_10,
color: Colors.black,
size: 30.w,
), ),
], ),
), ],
], ),
), ),
); );
} }
@ -313,9 +406,6 @@ class MeetingDetailsView extends GetView<MeetingDetailsController> {
onTap: () { onTap: () {
if (isActive) return; if (isActive) return;
controller.tabController.index = index; controller.tabController.index = index;
controller.isSpeakerText.value = false;
controller.editSpeakerTextId.value = 0;
controller.editSpeakerTextList = [];
}, },
child: Container( child: Container(
height: 45.w, height: 45.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,
); );

4
lib/modules/meeting/views/speaker_all_bottom_sheet.dart

@ -145,7 +145,9 @@ class _SpeakerAllBottomSheetState extends State<SpeakerAllBottomSheet> {
), ),
child: Focus( child: Focus(
onFocusChange: (bool hasFocus) { onFocusChange: (bool hasFocus) {
item['isShow'] = hasFocus; setState(() {
item['isShow'] = hasFocus;
});
}, },
child: TextField( child: TextField(
controller: item['speakerText'], controller: item['speakerText'],

66
lib/modules/meeting/views/speech_tab.dart

@ -21,7 +21,7 @@ class SpeechTab extends GetView<MeetingDetailsController> {
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
Map item = controller.textList[index]; Map item = controller.textList[index];
TextStyle textStyle = TextStyle( TextStyle textStyle = TextStyle(
fontSize: 16.sp, fontSize: 15.sp,
color: Colors.black87, color: Colors.black87,
letterSpacing: 0, letterSpacing: 0,
height: 1.4, height: 1.4,
@ -35,11 +35,11 @@ class SpeechTab extends GetView<MeetingDetailsController> {
children: [ children: [
if (item['speaker'].isNotEmpty) if (item['speaker'].isNotEmpty)
Container( Container(
width: 12.w, width: 11.w,
height: 12.w, height: 11.w,
margin: EdgeInsets.only(right: 2.w), margin: EdgeInsets.only(right: 3.w),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(28.r), borderRadius: BorderRadius.circular(11.r),
border: Border.all( border: Border.all(
color: const Color(0xFFFFC107), color: const Color(0xFFFFC107),
width: 3.w, width: 3.w,
@ -71,7 +71,7 @@ class SpeechTab extends GetView<MeetingDetailsController> {
item['speaker'], item['speaker'],
style: TextStyle( style: TextStyle(
color: const Color(0xFFFFC107), color: const Color(0xFFFFC107),
fontSize: 14.sp, fontSize: 13.sp,
), ),
), ),
), ),
@ -84,7 +84,7 @@ class SpeechTab extends GetView<MeetingDetailsController> {
), ),
style: TextStyle( style: TextStyle(
color: Colors.grey, color: Colors.grey,
fontSize: 14.sp, fontSize: 13.sp,
), ),
), ),
], ],
@ -151,16 +151,46 @@ class SpeechTab extends GetView<MeetingDetailsController> {
), ),
); );
} else { } else {
return Container( return Obx(() {
padding: EdgeInsets.symmetric( bool isActive = false;
horizontal: 14.w, int starttime = item['starttime'];
vertical: 5.w, int endtime = 0;
), if (index == controller.textList.length - 1) {
child: Text( endtime = controller.durationMax.value;
item['content'], } else {
style: textStyle, 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: () {
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 : Colors.black87,
letterSpacing: 0,
height: 1.4,
),
),
),
);
});
} }
}), }),
], ],
@ -183,6 +213,8 @@ class SpeechTab extends GetView<MeetingDetailsController> {
'编辑', '编辑',
() { () {
controller.isSpeakerText.value = true; controller.isSpeakerText.value = true;
controller.dragOffset.value = 0;
controller.isTop.value = true;
}, },
), ),
if (controller.meetingDetails.value.tasktype == 1 && if (controller.meetingDetails.value.tasktype == 1 &&

212
lib/modules/meeting/views/summary_tab.dart

@ -4,15 +4,117 @@ import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import '../../../data/services/db/sqflite_api.dart';
import '../controllers/meeting_details_controller.dart'; import '../controllers/meeting_details_controller.dart';
import 'speaker_all_bottom_sheet.dart'; import 'speaker_all_bottom_sheet.dart';
class SummaryTab extends GetView<MeetingDetailsController> { class SummaryTab extends StatefulWidget {
const SummaryTab({super.key}); const SummaryTab({super.key});
@override
State<SummaryTab> createState() => _SummaryTabState();
}
class _SummaryTabState extends State<SummaryTab> {
final _controller = Get.find<MeetingDetailsController>();
final String _addressPrefix = '地点:';
String _addressText = '';
final String _personnelPrefix = '与会人员:';
String _personnelText = '';
final TextEditingController _addressController = TextEditingController();
final TextEditingController _personnelController = TextEditingController();
@override
void initState() {
super.initState();
_addressController.text = _addressPrefix +
(_controller.meetingDetails.value.address.isNotEmpty
? _controller.meetingDetails.value.address
: '[输入地点]');
_personnelController.text = _personnelPrefix +
(_controller.meetingDetails.value.personnel.isNotEmpty
? _controller.meetingDetails.value.personnel
: '[输入与会人员]');
_addressController.addListener(_handleAddressChanged);
_personnelController.addListener(_handlePersonnelChanged);
}
void _handleAddressChanged() {
String currentText = _addressController.text;
TextSelection currentSelection = _addressController.selection;
if (!currentText.startsWith(_addressPrefix)) {
_addressController.value = TextEditingValue(
text: _addressPrefix + _addressText,
selection: TextSelection.collapsed(
offset: _addressPrefix.length + _addressText.length,
),
);
return;
} else {
_addressText = currentText.substring(_addressPrefix.length);
}
if (currentSelection.start < _addressPrefix.length ||
currentSelection.end < _addressPrefix.length) {
int newStart = currentSelection.start < _addressPrefix.length
? _addressPrefix.length
: currentSelection.start;
int newEnd = currentSelection.end < _addressPrefix.length
? _addressPrefix.length
: currentSelection.end;
_addressController.selection = currentSelection.copyWith(
baseOffset: newStart,
extentOffset: newEnd,
);
}
}
void _handlePersonnelChanged() {
String currentText = _personnelController.text;
TextSelection currentSelection = _personnelController.selection;
if (!currentText.startsWith(_personnelPrefix)) {
_personnelController.value = TextEditingValue(
text: _personnelPrefix + _personnelText,
selection: TextSelection.collapsed(
offset: _personnelPrefix.length + _personnelText.length,
),
);
return;
} else {
_personnelText = currentText.substring(_personnelPrefix.length);
}
if (currentSelection.start < _personnelPrefix.length ||
currentSelection.end < _personnelPrefix.length) {
int newStart = currentSelection.start < _personnelPrefix.length
? _personnelPrefix.length
: currentSelection.start;
int newEnd = currentSelection.end < _personnelPrefix.length
? _personnelPrefix.length
: currentSelection.end;
_personnelController.selection = currentSelection.copyWith(
baseOffset: newStart,
extentOffset: newEnd,
);
}
}
@override
void dispose() {
_addressController.dispose();
_personnelController.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark; final isDarkMode = Theme.of(context).brightness == Brightness.dark;
final TextStyle textStyle = TextStyle(
color: isDarkMode ? Colors.grey[400] : Colors.grey[700],
fontSize: 16.sp,
letterSpacing: 0,
height: 1.5,
);
return Stack( return Stack(
children: [ children: [
@ -25,7 +127,7 @@ class SummaryTab extends GetView<MeetingDetailsController> {
Padding( Padding(
padding: EdgeInsets.symmetric(vertical: 10.w), padding: EdgeInsets.symmetric(vertical: 10.w),
child: Text( child: Text(
controller.meetingData.value.title, _controller.meetingData.value.title,
style: TextStyle( style: TextStyle(
fontSize: 20.sp, fontSize: 20.sp,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -43,7 +145,7 @@ class SummaryTab extends GetView<MeetingDetailsController> {
borderRadius: BorderRadius.circular(4.w), borderRadius: BorderRadius.circular(4.w),
), ),
child: Text( child: Text(
controller.meetingData.value.type, _controller.meetingData.value.type,
style: TextStyle( style: TextStyle(
color: color:
isDarkMode ? Colors.grey[400] : Colors.grey[500], isDarkMode ? Colors.grey[400] : Colors.grey[500],
@ -59,7 +161,7 @@ class SummaryTab extends GetView<MeetingDetailsController> {
2.horizontalSpace, 2.horizontalSpace,
Text( Text(
DateUtil.formatDateMs( DateUtil.formatDateMs(
controller.meetingData.value.creationtime, _controller.meetingData.value.creationtime,
format: DateFormats.y_mo_d_h_m, format: DateFormats.y_mo_d_h_m,
), ),
style: TextStyle( style: TextStyle(
@ -75,7 +177,7 @@ class SummaryTab extends GetView<MeetingDetailsController> {
), ),
2.horizontalSpace, 2.horizontalSpace,
Text( Text(
'${controller.meetingData.value.seconds}s', '${_controller.meetingData.value.seconds}s',
style: TextStyle( style: TextStyle(
color: isDarkMode ? Colors.grey[400] : Colors.grey[500], color: isDarkMode ? Colors.grey[400] : Colors.grey[500],
fontSize: 12.sp, fontSize: 12.sp,
@ -103,43 +205,79 @@ class SummaryTab extends GetView<MeetingDetailsController> {
), ),
), ),
), ),
child: Column( child: Focus(
crossAxisAlignment: CrossAxisAlignment.start, onFocusChange: (bool hasFocus) {
children: [ if (!hasFocus) {
Text( bool isEdit = false;
'日期和时间:${DateUtil.formatDateMs( if (_addressText.isNotEmpty &&
controller.meetingData.value.creationtime, _addressText !=
format: DateFormats.y_mo_d_h_m, _controller.meetingDetails.value.address) {
)}', _controller.meetingDetails.value.address =
style: TextStyle( _addressText;
color: isEdit = true;
isDarkMode ? Colors.grey[400] : Colors.grey[700], }
fontSize: 16.sp, if (_personnelText.isNotEmpty &&
_personnelText !=
_controller.meetingDetails.value.personnel) {
_controller.meetingDetails.value.personnel =
_personnelText;
isEdit = true;
}
if (isEdit) {
SqfliteApi.editMeeting(
_controller.id,
{
'address':
_controller.meetingDetails.value.address,
'personnel':
_controller.meetingDetails.value.personnel,
},
);
}
}
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'日期和时间:${DateUtil.formatDateMs(
_controller.meetingData.value.creationtime,
format: DateFormats.y_mo_d_h_m,
)}',
style: textStyle,
), ),
), TextField(
Text( controller: _addressController,
'地点:${controller.meetingDetails.value.address.isNotEmpty ? controller.meetingDetails.value.address : '[输入地点]'}', style: textStyle,
style: TextStyle( minLines: 1,
color: maxLines: 100,
isDarkMode ? Colors.grey[400] : Colors.grey[700], decoration: const InputDecoration(
fontSize: 16.sp, isDense: true,
fillColor: Colors.transparent,
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
),
), ),
), TextField(
Text( controller: _personnelController,
'与会人员:${controller.meetingDetails.value.personnel.isNotEmpty ? controller.meetingDetails.value.personnel : '[输入与会人员]'}', style: textStyle,
style: TextStyle( minLines: 1,
color: maxLines: 100,
isDarkMode ? Colors.grey[400] : Colors.grey[700], decoration: const InputDecoration(
fontSize: 16.sp, isDense: true,
fillColor: Colors.transparent,
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
),
), ),
), ],
], ),
), ),
), ),
Padding( Padding(
padding: EdgeInsets.only(top: 10.w), padding: EdgeInsets.only(top: 10.w),
child: MarkdownBody( child: MarkdownBody(
data: controller.meetingDetails.value.summary, data: _controller.meetingDetails.value.summary,
), ),
), ),
], ],
@ -154,7 +292,7 @@ class SummaryTab extends GetView<MeetingDetailsController> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
if (controller.meetingDetails.value.summary.isNotEmpty) if (_controller.meetingDetails.value.summary.isNotEmpty)
_button( _button(
Icons.supervisor_account, Icons.supervisor_account,
'编辑发言者', '编辑发言者',
@ -174,13 +312,13 @@ class SummaryTab extends GetView<MeetingDetailsController> {
); );
}, },
), ),
if (controller.meetingDetails.value.summary.isEmpty) if (_controller.meetingDetails.value.summary.isEmpty)
SizedBox( SizedBox(
width: 150.w, width: 150.w,
child: _button( child: _button(
Icons.auto_awesome, Icons.auto_awesome,
'生成', '生成',
controller.summaryCreate, _controller.summaryCreate,
), ),
), ),
], ],

Loading…
Cancel
Save