Browse Source

feat(meeting): 支持思维导图暗色主题切换功能

- 使用 CSS 变量实现主题色动态切换,支持明暗两种模式
- 更新工具栏样式变量,保证样式在暗色模式下一致
- 移除默认暗色按钮,保留放大、缩小、适配窗口、递归展开功能
- 新增 window.updateTheme 方法供前端动态切换主题颜色
- 截图功能根据当前主题调整背景颜色,确保暗色截图正常
- 加载完成后自动应用当前主题,避免初始加载样式错乱
- MindMapController 新增 updateTheme 方法供外部调用切换主题
- MindMapTab 监听主题变化,及时通知控制器更新 WebView 显示
newdev_shunjiawei
lxm 7 months ago
parent
commit
51b82f8305
  1. 73
      lib/modules/meeting/controllers/mind_map_controller.dart
  2. 14
      lib/modules/meeting/views/tabs/mind_map_tab.dart

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

@ -41,6 +41,15 @@ class MindMapController extends GetxController {
<script>${_meetingDetailsController.markmapToolbarJs}</script> <script>${_meetingDetailsController.markmapToolbarJs}</script>
<script>${_meetingDetailsController.saveSvgAsPngJs}</script> <script>${_meetingDetailsController.saveSvgAsPngJs}</script>
<style> <style>
:root {
--bg-color: #FFFFFF;
--text-color: #000000;
--toolbar-bg: #FFFFFF;
--toolbar-border: #d0d5dd;
--toolbar-text: #101828;
--toolbar-active: #d4d4d8;
}
html, html,
body { body {
width: 100%; width: 100%;
@ -50,6 +59,8 @@ class MindMapController extends GetxController {
margin: 0; margin: 0;
padding: 0; padding: 0;
overflow: hidden; overflow: hidden;
background-color: var(--bg-color);
transition: background-color 0.3s ease;
} }
.mind-map { .mind-map {
@ -64,10 +75,15 @@ class MindMapController extends GetxController {
height: 100%; height: 100%;
} }
.mind-map #markmap .markmap-node-text {
fill: var(--text-color) !important;
transition: fill 0.3s ease;
}
.mind-map .mm-toolbar { .mind-map .mm-toolbar {
height: 30px; height: 30px;
background: #fff; background: var(--toolbar-bg);
border: 1px solid #d0d5dd; border: 1px solid var(--toolbar-border);
border-radius: 8px; border-radius: 8px;
display: flex; display: flex;
justify-content: space-around; justify-content: space-around;
@ -75,6 +91,7 @@ class MindMapController extends GetxController {
position: absolute; position: absolute;
top: 10px; top: 10px;
right: 2px; right: 2px;
transition: background 0.3s ease, border-color 0.3s ease;
} }
.mind-map .mm-toolbar-item { .mind-map .mm-toolbar-item {
@ -82,14 +99,15 @@ class MindMapController extends GetxController {
height: 24px; height: 24px;
border-radius: 6px; border-radius: 6px;
cursor: pointer; cursor: pointer;
color: #101828; color: var(--toolbar-text);
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
transition: color 0.3s ease;
} }
.mind-map .mm-toolbar-item.active { .mind-map .mm-toolbar-item.active {
background-color: #d4d4d8; background-color: var(--toolbar-active);
} }
</style> </style>
</head> </head>
@ -108,7 +126,9 @@ class MindMapController extends GetxController {
initialExpandLevel: 3, initialExpandLevel: 3,
}, root); }, root);
const toolbar = Toolbar.create(mm); const toolbar = Toolbar.create(mm);
toolbar.showBrand = false toolbar.showBrand = false;
// 只保留放大、缩小、适配窗口、递归展开;移除自带的 dark 按钮
toolbar.setItems(['zoomIn', 'zoomOut', 'fit', 'recurse']);
toolbar.render(); toolbar.render();
const el = toolbar.el; const el = toolbar.el;
const toolbarElement = document.getElementById('toolbar'); const toolbarElement = document.getElementById('toolbar');
@ -120,13 +140,40 @@ class MindMapController extends GetxController {
await mm.fit(); await mm.fit();
} }
// 动态切换主题颜色
window.updateTheme = function(isDark) {
const r = document.documentElement;
if (isDark) {
// 确保 markmap 内部暗色样式与 App 暗色主题一致
r.classList.add('markmap-dark');
r.style.setProperty('--bg-color', '#121212');
r.style.setProperty('--text-color', '#FFFFFF');
r.style.setProperty('--toolbar-bg', '#2D2D2D');
r.style.setProperty('--toolbar-border', '#404040');
r.style.setProperty('--toolbar-text', '#FFFFFF');
r.style.setProperty('--toolbar-active', '#404040');
} else {
// 还原为浅色主题
r.classList.remove('markmap-dark');
r.style.setProperty('--bg-color', '#FFFFFF');
r.style.setProperty('--text-color', '#000000');
r.style.setProperty('--toolbar-bg', '#FFFFFF');
r.style.setProperty('--toolbar-border', '#d0d5dd');
r.style.setProperty('--toolbar-text', '#101828');
r.style.setProperty('--toolbar-active', '#d4d4d8');
}
// 保存当前主题用于截图
window._isDarkTheme = isDark;
}
window.captureImage = async function() { window.captureImage = async function() {
const markmapElement = document.getElementById('markmap'); const markmapElement = document.getElementById('markmap');
markmapElement.style.height = `${_width}px`; markmapElement.style.height = `${_width}px`;
await mm.fit(); await mm.fit();
const bgColor = window._isDarkTheme ? '#121212' : '#FFFFFF';
const options = { const options = {
scale: 2, scale: 2,
backgroundColor: '#FFFFFF', backgroundColor: bgColor,
encoderOptions: 1, encoderOptions: 1,
}; };
const uri = await svgAsPngUri(markmapElement, options); const uri = await svgAsPngUri(markmapElement, options);
@ -147,6 +194,8 @@ class MindMapController extends GetxController {
NavigationDelegate( NavigationDelegate(
onPageFinished: (String url) { onPageFinished: (String url) {
isWebViewReady = true; isWebViewReady = true;
// 页面加载完成后立即应用当前主题
_applyCurrentTheme();
}, },
), ),
) )
@ -163,6 +212,18 @@ class MindMapController extends GetxController {
}); });
} }
/// 应用当前主题到 WebView
void _applyCurrentTheme() {
if (!isWebViewReady) return;
final isDark = Get.isDarkMode;
webViewController.runJavaScript('updateTheme($isDark)');
}
/// 供外部调用的主题更新方法
void updateTheme() {
_applyCurrentTheme();
}
@override @override
void onClose() { void onClose() {
_summaryNumberListener.dispose(); _summaryNumberListener.dispose();

14
lib/modules/meeting/views/tabs/mind_map_tab.dart

@ -15,9 +15,23 @@ class _MindMapTabState extends State<MindMapTab>
with AutomaticKeepAliveClientMixin { with AutomaticKeepAliveClientMixin {
final _controller = Get.find<MindMapController>(); final _controller = Get.find<MindMapController>();
// 缓存上一次的主题模式,用于检测变化
Brightness? _lastBrightness;
@override @override
bool get wantKeepAlive => true; bool get wantKeepAlive => true;
@override
void didChangeDependencies() {
super.didChangeDependencies();
final currentBrightness = Theme.of(context).brightness;
// 仅在主题实际变化时通知控制器更新 WebView
if (_lastBrightness != null && _lastBrightness != currentBrightness) {
_controller.updateTheme();
}
_lastBrightness = currentBrightness;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context); super.build(context);

Loading…
Cancel
Save