Files
xianyan/lib/features/file_transfer/services/clipboard_sync_service.dart
Developer 49b6323772 release: 发布6.6.18版本,完成多项合规与功能优化
此版本包含以下核心更新:
1. 版本号升级至6.6.18,更新全平台配置文件
2. 实现隐私合规改造:
   - 新增剪贴板隐私守卫,未同意协议前禁止读取剪贴板
   - 所有桌面小部件继承隐私感知基类,未同意协议时显示占位提示
   - 移除自动剪贴板监控,改为用户主动触发
3. 新增Windows平台深色主题同步功能
4. 补全多语言默认句子翻译
5. 优化安卓快捷方式配置与小部件合规性
6. 修复macOS插件注册问题
7. 新增Windows安装脚本
8. 优化触觉反馈服务初始化时机
2026-06-17 04:47:06 +08:00

113 lines
3.2 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ============================================================
// 闲言APP — 剪贴板同步服务
// 创建时间: 2026-05-10
// 更新时间: 2026-06-16
// 作用: 跨设备剪贴板文本同步 — 信令通道推送
// 上次更新: 使用ClipboardBridge统一入口含隐私协议守卫
// 未同意协议时禁止读取剪贴板
// ============================================================
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:xianyan/core/utils/logger.dart';
import 'package:xianyan/core/utils/platform/clipboard_bridge.dart';
import 'signaling_service.dart';
class ClipboardSyncService {
ClipboardSyncService({required SignalingService signalingService})
: _signalingService = signalingService;
final SignalingService _signalingService;
Timer? _pollTimer;
String? _lastClipboardText;
bool _isSyncing = false;
bool get isSyncing => _isSyncing;
final StreamController<String> _onRemoteClipboardController =
StreamController<String>.broadcast();
Stream<String> get onRemoteClipboard => _onRemoteClipboardController.stream;
void startSync({Duration interval = const Duration(seconds: 2)}) {
if (_isSyncing) return;
_isSyncing = true;
Log.i('ClipboardSync: Starting sync (interval: ${interval.inSeconds}s)');
_signalingService.onMessage.listen(_handleSignalingMessage);
_pollTimer = Timer.periodic(interval, (_) async {
await _checkLocalClipboard();
});
}
void stopSync() {
_isSyncing = false;
_pollTimer?.cancel();
_pollTimer = null;
Log.i('ClipboardSync: Stopped');
}
Future<void> _checkLocalClipboard() async {
try {
final text = await ClipboardBridge.getData();
if (text == null || text.isEmpty) return;
if (text == _lastClipboardText) return;
if (text.length > 10000) return;
_lastClipboardText = text;
_signalingService.sendCustomMessage(
SignalingMessage(
type: SignalingMessageType.clipboardSync,
from: _signalingService.deviceId ?? '',
payload: {'text': text},
),
);
Log.i('ClipboardSync: Sent clipboard (${text.length} chars)');
} catch (e) {
Log.w('ClipboardSync: Failed to read clipboard: $e');
}
}
void _handleSignalingMessage(SignalingMessage message) {
if (message.type != SignalingMessageType.clipboardSync) return;
final text = message.payload?['text'] as String?;
if (text == null) return;
_lastClipboardText = text;
Clipboard.setData(ClipboardData(text: text));
if (!_onRemoteClipboardController.isClosed) {
_onRemoteClipboardController.add(text);
}
Log.i(
'ClipboardSync: Received clipboard from ${message.from} (${text.length} chars)',
);
}
Future<void> sendText(String text) async {
_lastClipboardText = text;
_signalingService.sendCustomMessage(
SignalingMessage(
type: SignalingMessageType.clipboardSync,
from: _signalingService.deviceId ?? '',
payload: {'text': text},
),
);
Log.i('ClipboardSync: Manually sent text (${text.length} chars)');
}
Future<void> dispose() async {
stopSync();
await _onRemoteClipboardController.close();
}
}