This commit is contained in:
spasolreisa
2026-04-16 14:26:52 +08:00
commit 9ce601aa8d
151 changed files with 11467 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:encrypt/encrypt.dart' as enc;
import 'package:archive/archive.dart';
class EncryptionUtil {
// 固定密钥(和后端保持一致)
static const String _keyStr = ",Lscj312.;[]sc`1dsajcjc;;wislacx";
static const String _ivStr = ",>ew:[7890;,wd[2";
// 对外简易方法(你 Service / Provider 里直接用)
static String encrypt(String data) => encryptAndCompress(data);
static String decrypt(String encryptedBase64) => decompressAndDecrypt(encryptedBase64);
/// 加密:字符串 → GZIP → AES → Base64
static String encryptAndCompress(String plainText) {
// 强制 32位 Key / 16位 IVAES 标准)
final key = enc.Key.fromUtf8(_keyStr.padRight(32).substring(0, 32));
final iv = enc.IV.fromUtf8(_ivStr.padRight(16).substring(0, 16));
final encrypter = enc.Encrypter(enc.AES(key, mode: enc.AESMode.cbc));
// GZIP 压缩
final utf8Bytes = utf8.encode(plainText);
final compressed = GZipEncoder().encode(utf8Bytes)!;
// AES 加密
final encrypted = encrypter.encryptBytes(
Uint8List.fromList(compressed),
iv: iv,
);
return encrypted.base64;
}
/// 解密Base64 → AES → GZIP → 字符串
static String decompressAndDecrypt(String encryptedBase64) {
final key = enc.Key.fromUtf8(_keyStr.padRight(32).substring(0, 32));
final iv = enc.IV.fromUtf8(_ivStr.padRight(16).substring(0, 16));
final encrypter = enc.Encrypter(enc.AES(key, mode: enc.AESMode.cbc));
// 解密
final encrypted = enc.Encrypted.fromBase64(encryptedBase64);
final decryptedBytes = encrypter.decryptBytes(encrypted, iv: iv);
// GZIP 解压
final decompressed = GZipDecoder().decodeBytes(decryptedBytes);
return utf8.decode(decompressed);
}
}

117
lib/tool/gradientText.dart Normal file
View File

@@ -0,0 +1,117 @@
import 'package:flutter/material.dart';
class GradientLayer {
final Gradient gradient;
final BlendMode blendMode;
const GradientLayer({
required this.gradient,
this.blendMode = BlendMode.srcIn, // 默认第一层用 srcIn 打底
});
}
class GradientText extends StatelessWidget {
final String data;
final TextStyle? style;
final TextAlign? textAlign;
final TextDirection? textDirection;
final bool softWrap;
final TextOverflow? overflow;
final double? textScaleFactor;
final int? maxLines;
final Locale? locale;
final String? semanticsLabel;
final TextWidthBasis? textWidthBasis;
final TextHeightBehavior? textHeightBehavior;
final List<GradientLayer> gradientLayers;
const GradientText({
Key? key,
required this.data,
this.style,
this.textAlign,
this.textDirection,
this.softWrap = true,
this.overflow,
this.textScaleFactor,
this.maxLines,
this.locale,
this.semanticsLabel,
this.textWidthBasis,
this.textHeightBehavior,
this.gradientLayers = const [],
}) : super(key: key);
@override
Widget build(BuildContext context) {
if (gradientLayers.isEmpty) {
return Text(
data,
style: style,
textAlign: textAlign,
textDirection: textDirection,
softWrap: softWrap,
overflow: overflow,
textScaleFactor: textScaleFactor,
maxLines: maxLines,
locale: locale,
semanticsLabel: semanticsLabel,
textWidthBasis: textWidthBasis,
textHeightBehavior: textHeightBehavior,
);
}
final baseStyle = style ?? const TextStyle();
return Stack(
children: [
// 1. 最底层:纯色文本(可选,防止所有渐变都透明时看不见)
// 如果第一层渐变是 srcIn这一层其实可以被遮挡但保留它作为“备用底色”
Opacity(
opacity: 0.0, // 隐藏,仅占位
child: _buildText(baseStyle.copyWith(color: Colors.black)),
),
// 2. 叠加渐变层
...gradientLayers.asMap().entries.map((entry) {
final index = entry.key;
final layer = entry.value;
// 关键逻辑:
// 如果是第一层且用户没改 blendMode默认用 srcIn 确保文字有颜色
// 如果是后续层,通常希望融合,所以建议用户传入 overlay/plus 等
return ShaderMask(
shaderCallback: (Rect bounds) {
return layer.gradient.createShader(bounds);
},
blendMode: layer.blendMode,
child: _buildText(
// 重要:为了融合效果,内部文本通常是白色或浅色
// 如果 blendMode 是 srcIn颜色不重要会被渐变替换
// 如果 blendMode 是 overlay/plus白色能让渐变颜色最纯正地显示
baseStyle.copyWith(color: Colors.white),
),
);
}).toList(),
],
);
}
Widget _buildText(TextStyle effectiveStyle) {
return Text(
data,
style: effectiveStyle,
textAlign: textAlign,
textDirection: textDirection,
softWrap: softWrap,
overflow: overflow,
textScaleFactor: textScaleFactor,
maxLines: maxLines,
locale: locale,
semanticsLabel: semanticsLabel,
textWidthBasis: textWidthBasis,
textHeightBehavior: textHeightBehavior,
);
}
}