beta v0.2 dualcheck

This commit is contained in:
cancerai committed 2026-08-30 21:25:22 +08:00
1 parent c137299016
commit 1ec68bacf5
14 files changed
+1591 -359

No files matched your search

@@ -1,8 +1,13 @@
// 全局昵称设置
// 持久化到 SharedPreferences / localStorage,所有工具共享同一个昵称
// Web 平台自动监听 localStorage 变化 → 跨标签页实时同步
import 'dart:async';
import 'dart:html' as html show window, StorageEvent;
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:shared_preferences/shared_preferences.dart';
const _keyNickname = 'toolbox.nickname';
const _keyBrowserId = 'toolbox.browser_id';
class NicknameService {
NicknameService._();
@@ -10,8 +15,60 @@ class NicknameService {
SharedPreferences? _prefs;
/// 浏览器唯一 ID:同浏览器跨 tab 共享(localStorage 作用域),跨浏览器不同
/// 用于后端识别"同一个人",避免昵称冲突时自动改名
String? _browserId;
/// 昵称变化广播流:本地 setNickname 触发 + Web 上其他标签页修改也触发
final _streamController = StreamController<String>.broadcast();
Stream<String> get onChanged => _streamController.stream;
StreamSubscription? _webStorageSub;
Future<void> _ensureInit() async {
_prefs ??= await SharedPreferences.getInstance();
// 惰性生成 browserId:首次访问时若没有就生成 uuid 存起来
if (_browserId == null) {
final existing = _prefs!.getString(_keyBrowserId);
if (existing != null && existing.isNotEmpty) {
_browserId = existing;
} else {
_browserId = _genBrowserId();
await _prefs!.setString(_keyBrowserId, _browserId!);
}
}
}
/// 获取浏览器 ID(稳定值,同浏览器跨 tab 相同)
Future<String> get browserId async {
await _ensureInit();
return _browserId!;
}
/// 生成短 browserId:base62(0-9A-Za-z),去掉特殊字符方便 URL 使用
/// 12 字符足够唯一(62^12 ≈ 3e21 种可能)
String _genBrowserId() {
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
final rand = DateTime.now().microsecond.hashCode;
final buf = StringBuffer();
int seed = rand ^ DateTime.now().millisecondsSinceEpoch;
for (int i = 0; i < 12; i++) {
seed = (seed * 1103515245 + 12345) & 0x7FFFFFFF;
buf.write(chars[seed % chars.length]);
}
return buf.toString();
}
/// 开启跨标签页同步(仅 Web 生效;非 Web 空操作)
/// 在 widget 的 initState 里调用一次即可
void enableCrossTabSync() {
if (!kIsWeb || _webStorageSub != null) return;
_webStorageSub = html.window.onStorage.listen((html.StorageEvent event) async {
if (event.key == _keyNickname) {
final n = await nickname;
_streamController.add(n);
}
});
}
/// 获取当前昵称,未设置时返回默认昵称
@@ -28,6 +85,12 @@ class NicknameService {
if (trimmed.isEmpty || trimmed.length > 32) return false;
await _ensureInit();
await _prefs!.setString(_keyNickname, trimmed);
_streamController.add(trimmed);
return true;
}
void dispose() {
_webStorageSub?.cancel();
_webStorageSub = null;
}
}