Browse Source

优化思维导图分享

weicu
tanlongsheng 1 year ago
parent
commit
4b6bb2c760
  1. 2
      lib/modules/meeting/bindings/meeting_details_binding.dart
  2. 155
      lib/modules/meeting/controllers/mind_map_controller.dart
  3. 143
      lib/modules/meeting/views/mind_map_tab.dart
  4. 12
      lib/modules/meeting/views/share_bottom_sheet.dart

2
lib/modules/meeting/bindings/meeting_details_binding.dart

@ -1,10 +1,12 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import '../controllers/meeting_details_controller.dart'; import '../controllers/meeting_details_controller.dart';
import '../controllers/mind_map_controller.dart';
class MeetingDetailsBinding extends Bindings { class MeetingDetailsBinding extends Bindings {
@override @override
void dependencies() { void dependencies() {
// 注册控制器 // 注册控制器
Get.lazyPut<MeetingDetailsController>(() => MeetingDetailsController()); Get.lazyPut<MeetingDetailsController>(() => MeetingDetailsController());
Get.lazyPut<MindMapController>(() => MindMapController());
} }
} }

155
lib/modules/meeting/controllers/mind_map_controller.dart

@ -0,0 +1,155 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
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:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'meeting_details_controller.dart';
class MindMapController extends GetxController {
late final WebViewController webViewController;
final _meetingDetailsController = Get.find<MeetingDetailsController>();
@override
void onInit() {
super.onInit();
String html = '''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MindMap</title>
<script src="https://cdn.jsdelivr.net/npm/markmap-lib"></script>
<script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
<script src="https://cdn.jsdelivr.net/npm/markmap-view"></script>
<script src="https://cdn.jsdelivr.net/npm/markmap-toolbar"></script>
<script src="https://cdn.jsdelivr.net/npm/save-svg-as-png@1.4.17/lib/saveSvgAsPng.min.js"></script>
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.mind-map {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
.mind-map #markmap {
width: 100%;
height: 100%;
}
.mind-map .mm-toolbar {
height: 30px;
background: #fff;
border: 1px solid #d0d5dd;
border-radius: 8px;
display: flex;
justify-content: space-around;
align-items: center;
position: absolute;
top: 20px;
right: 20px;
}
.mind-map .mm-toolbar-item {
width: 24px;
height: 24px;
border-radius: 6px;
cursor: pointer;
color: #101828;
display: flex;
justify-content: center;
align-items: center;
}
.mind-map .mm-toolbar-item.active {
background-color: #d4d4d8;
}
</style>
</head>
<body>
<div class="mind-map">
<svg id="markmap"></svg>
<div id="toolbar"></div>
</div>
<script>
const { Transformer, Markmap, Toolbar } = window.markmap;
const transformer = new Transformer();
const { root } = transformer.transform(`${_meetingDetailsController.meetingDetails.value.summary}`);
let mm = Markmap.create('#markmap', {
maxWidth: 300,
initialExpandLevel: 3,
}, root);
const toolbar = Toolbar.create(mm);
toolbar.showBrand = false
toolbar.render();
const el = toolbar.el;
const toolbarElement = document.getElementById('toolbar');
toolbarElement.append(el);
async function captureImage() {
const markmapElement = document.getElementById('markmap');
markmapElement.style.height = `${1.sw}px`;
await mm.fit();
const options = {
scale: 2,
backgroundColor: '#FFFFFF',
encoderOptions: 1,
};
const uri = await svgAsPngUri(markmapElement, options);
markmapElement.style.height = '100%';
mm.fit();
if (window.ImageChannel) {
window.ImageChannel.postMessage(uri);
}
}
</script>
</body>
</html>
''';
webViewController = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..addJavaScriptChannel(
'ImageChannel',
onMessageReceived: _messageReceived,
)
..setBackgroundColor(Colors.transparent)
..loadHtmlString(html);
}
void _messageReceived(message) async {
final String dataUrl = message.message;
final String base64Str = dataUrl.split(',').last;
final Uint8List bytes = base64.decode(base64Str);
final String fileName =
'${_meetingDetailsController.meetingData.value.title} mindmap.png';
final tempDir = await getTemporaryDirectory();
final File file = File('${tempDir.path}/$fileName');
await file.writeAsBytes(bytes);
final result = await SharePlus.instance.share(ShareParams(
text: '分享思维导图',
files: [XFile(file.path)],
));
if (result.status == ShareResultStatus.success) {
EasyLoading.showToast('分享完成!');
}
}
}

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

@ -1,9 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:webview_flutter/webview_flutter.dart'; import 'package:webview_flutter/webview_flutter.dart';
import '../controllers/meeting_details_controller.dart'; import '../controllers/mind_map_controller.dart';
class MindMapTab extends StatefulWidget { class MindMapTab extends StatefulWidget {
const MindMapTab({super.key}); const MindMapTab({super.key});
@ -14,129 +13,7 @@ class MindMapTab extends StatefulWidget {
class _MindMapTabState extends State<MindMapTab> class _MindMapTabState extends State<MindMapTab>
with AutomaticKeepAliveClientMixin { with AutomaticKeepAliveClientMixin {
late final WebViewController _controller; final _controller = Get.find<MindMapController>();
final _meetingDetailsController = Get.find<MeetingDetailsController>();
@override
void initState() {
super.initState();
String html = '''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MindMap</title>
<script src="https://cdn.jsdelivr.net/npm/markmap-lib"></script>
<script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
<script src="https://cdn.jsdelivr.net/npm/markmap-view"></script>
<script src="https://cdn.jsdelivr.net/npm/markmap-toolbar"></script>
<script src="https://cdn.jsdelivr.net/npm/save-svg-as-png@1.4.17/lib/saveSvgAsPng.min.js"></script>
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.mind-map {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
.mind-map #markmap {
width: 100%;
height: 100%;
}
.mind-map .mm-toolbar {
height: 30px;
background: #fff;
border: 1px solid #d0d5dd;
border-radius: 8px;
display: flex;
justify-content: space-around;
align-items: center;
position: absolute;
top: 20px;
right: 20px;
}
.mind-map .mm-toolbar-item {
width: 24px;
height: 24px;
border-radius: 6px;
cursor: pointer;
color: #101828;
display: flex;
justify-content: center;
align-items: center;
}
.mind-map .mm-toolbar-item.active {
background-color: #d4d4d8;
}
</style>
</head>
<body>
<div class="mind-map">
<svg id="markmap"></svg>
<div id="toolbar"></div>
</div>
<script>
const { Transformer, Markmap, Toolbar } = window.markmap;
const transformer = new Transformer();
const { root } = transformer.transform(`${_meetingDetailsController.meetingDetails.value.summary}`);
let mm = Markmap.create('#markmap', {
maxWidth: 300,
initialExpandLevel: 3,
}, root);
const toolbar = Toolbar.create(mm);
toolbar.showBrand = false
toolbar.render();
const el = toolbar.el;
const toolbarElement = document.getElementById('toolbar');
toolbarElement.append(el);
async function captureImage() {
const markmapElement = document.getElementById('markmap');
markmapElement.style.height = `${1.sw}px`;
await mm.fit();
const options = {
scale: 2,
backgroundColor: '#FFFFFF',
encoderOptions: 1,
};
const uri = await svgAsPngUri(markmapElement, options);
markmapElement.style.height = '100%';
await mm.fit();
if (window.ImageChannel) {
window.ImageChannel.postMessage(uri);
}
}
</script>
</body>
</html>
''';
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..addJavaScriptChannel(
'ImageChannel',
onMessageReceived: (message) {
print('-------${message.message}------');
},
)
..setBackgroundColor(Colors.transparent)
..loadHtmlString(html);
}
@override @override
bool get wantKeepAlive => true; bool get wantKeepAlive => true;
@ -144,20 +21,8 @@ class _MindMapTabState extends State<MindMapTab>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context); super.build(context);
return Column( return WebViewWidget(
children: [ controller: _controller.webViewController,
InkWell(
child: Text('保存111111'),
onTap: () async {
await _controller.runJavaScript('captureImage()');
},
),
Expanded(
child: WebViewWidget(
controller: _controller,
),
),
],
); );
} }
} }

12
lib/modules/meeting/views/share_bottom_sheet.dart

@ -11,6 +11,7 @@ import 'package:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
import '../controllers/meeting_details_controller.dart'; import '../controllers/meeting_details_controller.dart';
import '../controllers/mind_map_controller.dart';
class ShareBottomSheet extends StatefulWidget { class ShareBottomSheet extends StatefulWidget {
const ShareBottomSheet({super.key}); const ShareBottomSheet({super.key});
@ -125,28 +126,33 @@ class _ShareBottomSheetState extends State<ShareBottomSheet> {
_share(_controller.meetingData.value.filepath, '分享会议音频'); _share(_controller.meetingData.value.filepath, '分享会议音频');
}), }),
_shareItem(Icons.message, '导出转写', onTap: () async { _shareItem(Icons.message, '导出转写', onTap: () async {
Get.back();
final tempDir = await getTemporaryDirectory(); final tempDir = await getTemporaryDirectory();
final file = File( final file = File(
'${tempDir.path}/${_controller.meetingData.value.title} speaker.txt'); '${tempDir.path}/${_controller.meetingData.value.title} speaker.txt');
String allText = _getAllText(); String allText = _getAllText();
await file.writeAsString(allText); await file.writeAsString(allText);
Get.back();
_share(file.path, '分享会议转写'); _share(file.path, '分享会议转写');
}), }),
_shareItem(Icons.article, '导出总结', onTap: () async { _shareItem(Icons.article, '导出总结', onTap: () async {
Get.back();
final tempDir = await getTemporaryDirectory(); final tempDir = await getTemporaryDirectory();
final file = File( final file = File(
'${tempDir.path}/${_controller.meetingData.value.title} summary.txt'); '${tempDir.path}/${_controller.meetingData.value.title} summary.txt');
await file.writeAsString( await file.writeAsString(
_controller.meetingDetails.value.summary); _controller.meetingDetails.value.summary);
Get.back();
_share(file.path, '分享会议总结'); _share(file.path, '分享会议总结');
}), }),
_shareItem( _shareItem(
Icons.lan, Icons.lan,
'导出思维导图', '导出思维导图',
isBorder: false, isBorder: false,
onTap: () {}, onTap: () {
Get.back();
final mindMapController = Get.find<MindMapController>();
mindMapController.webViewController
.runJavaScript('captureImage()');
},
), ),
]), ]),
], ],

Loading…
Cancel
Save