feat: 新增壁纸图库组件和编辑器功能优化

- 新增壁纸图库相关组件(WallpaperGalleryView/WallpaperSearchBar等)
- 优化编辑器主题服务和系统UI管理
- 新增虚线边框和拖拽描边风格支持
- 完善今日诗词服务和阅读报告功能
- 修复多个UI问题和空指针异常
- 更新依赖库版本和SVG资源
- 优化交互动画和状态管理
- 补充文档和API测试脚本
This commit is contained in:
Developer
2026-05-05 05:03:33 +08:00
parent 839e118cdb
commit b5157c19f4
230 changed files with 44325 additions and 19116 deletions

196
scripts/api_verify.dart Normal file
View File

@@ -0,0 +1,196 @@
// ============================================================
// 闲言APP — 接口连通性验证脚本
// 创建时间: 2026-05-02
// 更新时间: 2026-05-02
// 作用: 验证壁纸API + 今日诗词SDK的连通性和性能
// 上次更新: 初始创建
// ============================================================
// 使用方法: dart run scripts/api_verify.dart
import 'dart:convert';
import 'dart:io';
void main() async {
print('═══════════════════════════════════════════');
print(' 闲言APP — 接口连通性验证');
print(' ${DateTime.now().toIso8601String()}');
print('═══════════════════════════════════════════\n');
// 1. 壁纸 API
await _verifyWallpaperApi();
// 2. 今日诗词 SDK
await _verifyJinrishiciSdk();
print('\n═══════════════════════════════════════════');
print(' 验证完成');
print('═══════════════════════════════════════════');
}
Future<void> _verifyWallpaperApi() async {
print('┌─────────────────────────────────────────┐');
print('│ 🖼️ 壁纸 API 验证 │');
print('└─────────────────────────────────────────┘\n');
final baseUrl = 'http://bz.wktyl.com';
final endpoints = [
{
'name': 'Unsplash',
'path': '/api_unsplash.php',
'params': 'limit=5&page=1',
},
{
'name': '360壁纸',
'path': '/api_360_bing.php',
'params': 'limit=5&page=1&source=360',
},
{
'name': '必应壁纸',
'path': '/api_360_bing.php',
'params': 'limit=5&page=1&source=bing',
},
{'name': 'Pexels', 'path': '/api_pexels.php', 'params': 'limit=5&page=1'},
{'name': 'Pixabay', 'path': '/api_pixabay.php', 'params': 'limit=5&page=1'},
{
'name': 'WallSt',
'path': '/api_wallstreet.php',
'params': 'limit=5&page=1',
},
];
for (final ep in endpoints) {
final url = '$baseUrl${ep['path']}?${ep['params']}';
await _testEndpoint(ep['name']!, url);
}
}
Future<void> _verifyJinrishiciSdk() async {
print('\n┌─────────────────────────────────────────┐');
print('│ 📜 今日诗词 SDK 验证 │');
print('└─────────────────────────────────────────┘\n');
// Step 1: Token
final tokenUrl = 'https://v2.jinrishici.com/token';
String? token;
final tokenResult = await _testEndpoint('Token 获取', tokenUrl);
if (tokenResult != null) {
try {
final data = jsonDecode(tokenResult) as Map<String, dynamic>;
token = data['data'] as String?;
if (token != null) {
print(' ✅ Token: ${token.substring(0, 20)}...');
}
} catch (e) {
print(' ⚠️ Token 解析失败: $e');
}
}
// Step 2: Sentence
final sentenceUrl = 'https://v2.jinrishici.com/sentence';
final headers = token != null ? {'X-User-Token': token} : <String, String>{};
final sentenceResult = await _testEndpoint(
'每日诗词',
sentenceUrl,
headers: headers,
);
if (sentenceResult != null) {
try {
final data = jsonDecode(sentenceResult) as Map<String, dynamic>;
final content = data['data']?['content'] as String?;
final origin = data['data']?['origin'] as Map<String, dynamic>?;
final title = origin?['title'] as String?;
final author = origin?['author'] as String?;
final dynasty = origin?['dynasty'] as String?;
print(' 📝 内容: $content');
print(' 📖 来源: 《$title${dynasty ?? ''}·${author ?? ''}');
} catch (e) {
print(' ⚠️ 诗词解析失败: $e');
}
}
// Step 3: Info (天气数据)
final infoUrl = 'https://v2.jinrishici.com/info';
final infoResult = await _testEndpoint('用户信息+天气', infoUrl, headers: headers);
if (infoResult != null) {
try {
final data = jsonDecode(infoResult) as Map<String, dynamic>;
final infoData = data['data'] as Map<String, dynamic>?;
final region = infoData?['region'] as String?;
final weatherData = infoData?['weatherData'] as Map<String, dynamic>?;
print(' 📍 地区: $region');
if (weatherData != null) {
print(' 🌡️ 温度: ${weatherData['temperature']}°C');
print(' 🌤️ 天气: ${weatherData['weather']}');
print(' 💧 湿度: ${weatherData['humidity']}%');
print(' 🌬️ 风向: ${weatherData['windDirection']}');
print(' 💨 风力: ${weatherData['windPower']}');
if (weatherData['pm25'] != null) {
print(' 🫁 PM2.5: ${weatherData['pm25']}');
}
}
} catch (e) {
print(' ⚠️ 信息解析失败: $e');
}
}
}
Future<String?> _testEndpoint(
String name,
String url, {
Map<String, String>? headers,
}) async {
final sw = Stopwatch()..start();
try {
final client = HttpClient();
client.connectionTimeout = const Duration(seconds: 10);
final request = await client.getUrl(Uri.parse(url));
headers?.forEach((k, v) => request.headers.set(k, v));
final response = await request.close();
final body = await response.transform(utf8.decoder).join();
sw.stop();
final status = response.statusCode;
final ms = sw.elapsedMilliseconds;
final size = body.length;
final statusIcon = status == 200 ? '' : '';
final perfIcon = ms < 500
? '🟢'
: ms < 2000
? '🟡'
: '🔴';
print(' $statusIcon $name');
print(' URL: $url');
print(
' 状态码: $status | 响应时间: ${ms}ms $perfIcon | 大小: ${_formatSize(size)}',
);
if (status != 200) {
print(
' 响应: ${body.substring(0, body.length > 200 ? 200 : body.length)}',
);
}
client.close();
return status == 200 ? body : null;
} catch (e) {
sw.stop();
print('$name');
print(' URL: $url');
print(' 错误: $e (${sw.elapsedMilliseconds}ms)');
return null;
}
}
String _formatSize(int bytes) {
if (bytes < 1024) return '$bytes B';
if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)} KB';
return '${(bytes / (1024 * 1024)).toStringAsFixed(1)} MB';
}