feat: 新增壁纸图库组件和编辑器功能优化
- 新增壁纸图库相关组件(WallpaperGalleryView/WallpaperSearchBar等) - 优化编辑器主题服务和系统UI管理 - 新增虚线边框和拖拽描边风格支持 - 完善今日诗词服务和阅读报告功能 - 修复多个UI问题和空指针异常 - 更新依赖库版本和SVG资源 - 优化交互动画和状态管理 - 补充文档和API测试脚本
This commit is contained in:
173
lib/features/template/models/template_models.dart
Normal file
173
lib/features/template/models/template_models.dart
Normal file
@@ -0,0 +1,173 @@
|
||||
/// ============================================================
|
||||
/// 闲言APP — 壁纸模板数据模型
|
||||
/// 创建时间: 2026-05-01
|
||||
/// 更新时间: 2026-05-04
|
||||
// 作用: 壁纸图库数据结构 — 壁纸项/分类/来源/模板
|
||||
// 上次更新: tags字段类型保护(is List检查)防API返回非List崩溃
|
||||
/// ============================================================
|
||||
|
||||
// ============================================================
|
||||
// 壁纸来源
|
||||
// ============================================================
|
||||
|
||||
enum WallpaperSource {
|
||||
unsplash('api_unsplash', '📷', 'photo', 'Unsplash', 138),
|
||||
wallstreet('api_wallstreet', '🏙', 'square_grid_2x2', 'WallSt', 140),
|
||||
pexels('api_pexels', '🎞', 'photo', 'Pexels', 136),
|
||||
pixabay('api_pixabay', '🔍', 'circle_grid_3x3', 'Pixabay', 140),
|
||||
bing360('api_360_bing', '🖼', 'photo', '360壁纸', 264),
|
||||
bing('api_360_bing', '🌍', 'globe', '必应壁纸', 245),
|
||||
nasa('api_nasa', '🚀', 'sparkles', 'NASA', 133),
|
||||
haoWallpaper('api_hao_wallpaper', '🏔', 'square_grid_2x2', '精选壁纸', 345),
|
||||
bizhiduoduo('api_bizhiduoduo', '🎲', 'square_grid_2x2', '多多壁纸', 2102),
|
||||
bingEnhanced('api_bing_enhanced', '🔮', 'sparkles', '增强必应', 371),
|
||||
animePictures('api_anime_pictures', '🎨', 'paintpalette', '动漫插画', 2432),
|
||||
dmoe('api_dmoe', '🌸', 'sparkles', '二次元', 2807);
|
||||
|
||||
const WallpaperSource(
|
||||
this.path,
|
||||
this.emoji,
|
||||
this.iconName,
|
||||
this.label,
|
||||
this.avgMs,
|
||||
);
|
||||
final String path;
|
||||
final String emoji;
|
||||
final String iconName;
|
||||
final String label;
|
||||
final int avgMs;
|
||||
|
||||
String get baseUrl => 'http://bz.wktyl.com';
|
||||
|
||||
String buildUrl({
|
||||
int limit = 20,
|
||||
int page = 1,
|
||||
String? category,
|
||||
String sort = 'hot',
|
||||
String? search,
|
||||
}) {
|
||||
final params = <String, String>{'limit': '$limit', 'page': '$page'};
|
||||
if (this == WallpaperSource.bing360) {
|
||||
params['source'] = '360';
|
||||
} else if (this == WallpaperSource.bing) {
|
||||
params['source'] = 'bing';
|
||||
} else if (this == WallpaperSource.bizhiduoduo) {
|
||||
params['action'] = 'random';
|
||||
}
|
||||
if (category != null && category != 'all') params['category'] = category;
|
||||
if (sort != 'hot') params['sort'] = sort;
|
||||
if (search != null && search.isNotEmpty) params['search'] = search;
|
||||
|
||||
final query = params.entries.map((e) => '${e.key}=${e.value}').join('&');
|
||||
return '$baseUrl/$path.php?$query';
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 壁纸数据项
|
||||
// ============================================================
|
||||
|
||||
class WallpaperItem {
|
||||
const WallpaperItem({
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.imageUrl,
|
||||
required this.thumbnailUrl,
|
||||
required this.previewUrl,
|
||||
this.downloadUrl,
|
||||
this.width = 0,
|
||||
this.height = 0,
|
||||
this.resolution = '',
|
||||
this.format = '',
|
||||
this.fileSize = 0,
|
||||
this.views = 0,
|
||||
this.downloads = 0,
|
||||
this.likes = 0,
|
||||
this.popularityScore = 0.0,
|
||||
this.tags = const [],
|
||||
this.primaryCategory = '',
|
||||
this.source = '',
|
||||
this.sourceType = '',
|
||||
});
|
||||
|
||||
final String id;
|
||||
final String title;
|
||||
final String imageUrl;
|
||||
final String thumbnailUrl;
|
||||
final String previewUrl;
|
||||
final String? downloadUrl;
|
||||
final int width;
|
||||
final int height;
|
||||
final String resolution;
|
||||
final String format;
|
||||
final int fileSize;
|
||||
final int views;
|
||||
final int downloads;
|
||||
final int likes;
|
||||
final double popularityScore;
|
||||
final List<String> tags;
|
||||
final String primaryCategory;
|
||||
final String source;
|
||||
final String sourceType;
|
||||
|
||||
double get aspectRatio => width > 0 && height > 0 ? width / height : 9 / 16;
|
||||
|
||||
factory WallpaperItem.fromApi(Map<String, dynamic> json) {
|
||||
final resourceInfo = json['resource_info'] as Map<String, dynamic>? ?? {};
|
||||
final media = json['media'] as Map<String, dynamic>? ?? {};
|
||||
final classification =
|
||||
json['classification'] as Map<String, dynamic>? ?? {};
|
||||
final statistics = json['statistics'] as Map<String, dynamic>? ?? {};
|
||||
final metadata = json['metadata'] as Map<String, dynamic>? ?? {};
|
||||
|
||||
return WallpaperItem(
|
||||
id: json['id']?.toString() ?? '',
|
||||
title: resourceInfo['title'] as String? ?? '',
|
||||
imageUrl: media['image_url'] as String? ?? '',
|
||||
thumbnailUrl: media['thumbnail_url'] as String? ?? '',
|
||||
previewUrl: media['preview_url'] as String? ?? '',
|
||||
downloadUrl: media['download_url'] as String?,
|
||||
width: (media['width'] as num?)?.toInt() ?? 0,
|
||||
height: (media['height'] as num?)?.toInt() ?? 0,
|
||||
resolution: media['resolution'] as String? ?? '',
|
||||
format: media['format'] as String? ?? '',
|
||||
fileSize: (media['file_size'] as num?)?.toInt() ?? 0,
|
||||
views: (statistics['views'] as num?)?.toInt() ?? 0,
|
||||
downloads: (statistics['downloads'] as num?)?.toInt() ?? 0,
|
||||
likes: (statistics['likes'] as num?)?.toInt() ?? 0,
|
||||
popularityScore:
|
||||
(statistics['popularity_score'] as num?)?.toDouble() ?? 0.0,
|
||||
tags: (classification['tags'] is List<dynamic>)
|
||||
? (classification['tags'] as List<dynamic>)
|
||||
.map((e) => e.toString())
|
||||
.toList()
|
||||
: [],
|
||||
primaryCategory: classification['primary_category'] as String? ?? '',
|
||||
source: metadata['source'] as String? ?? '',
|
||||
sourceType: resourceInfo['source_type'] as String? ?? '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 壁纸分类
|
||||
// ============================================================
|
||||
|
||||
enum WallpaperCategory {
|
||||
all('all', '🌐', 'globe', '全部'),
|
||||
nature('nature', '🌿', 'circle', '自然'),
|
||||
animal('animal', '🐾', 'smiley', '动物'),
|
||||
architecture('architecture', '🏛', 'square_grid_2x2', '建筑'),
|
||||
technology('technology', '💻', 'pencil_ellipsis', '科技'),
|
||||
abstract('abstract', '🎨', 'paintpalette', '抽象'),
|
||||
people('people', '👤', 'smiley', '人物'),
|
||||
travel('travel', '✈️', 'globe', '旅行'),
|
||||
food('food', '🍜', 'drop', '美食'),
|
||||
anime('anime', '🌸', 'sparkles', '动漫');
|
||||
|
||||
const WallpaperCategory(this.id, this.emoji, this.iconName, this.label);
|
||||
final String id;
|
||||
final String emoji;
|
||||
final String iconName;
|
||||
final String label;
|
||||
}
|
||||
Reference in New Issue
Block a user