Files
xianyan/lib/features/template/models/template_models.dart
Developer 83720002e6 feat: 新增工作台模式、系统托盘,修复多平台兼容性问题
1. 新增工作台三栏布局模式,适配宽屏设备
2. 添加跨平台系统托盘支持,新增托盘图标资源
3. 修复工作台模式下导航返回异常问题
4. 统一JSON类型安全解析,替换硬类型转换
5. 增加macOS深度链接支持,统一渠道分发信息
6. 优化部分页面生命周期和状态加载逻辑
7. 移除废弃的nearby_connections依赖
2026-06-19 06:43:55 +08:00

208 lines
7.1 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-01
/// 更新时间: 2026-06-19
// 作用: 壁纸图库数据结构 — 壁纸项/分类/来源/模板
// 上次更新: 修复筛选类型与实际不一致——不支持分类的源跳过category参数
/// ============================================================
// ============================================================
// 壁纸来源
// ============================================================
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;
bool get isFast => avgMs < 500;
/// 是否支持分类筛选
///
/// 以下源不支持分类筛选(返回随机或固定内容):
/// - bing360 / bing: 必应每日壁纸,无分类
/// - nasa: NASA每日天文图片无分类
/// - dmoe: 随机二次元壁纸,无分类
/// - animePictures: 随机动漫插画,无分类
/// - bizhiduoduo: action=random 模式category 无效
bool get supportsCategory {
switch (this) {
case WallpaperSource.bing360:
case WallpaperSource.bing:
case WallpaperSource.nasa:
case WallpaperSource.dmoe:
case WallpaperSource.animePictures:
case WallpaperSource.bizhiduoduo:
return false;
case WallpaperSource.unsplash:
case WallpaperSource.wallstreet:
case WallpaperSource.pexels:
case WallpaperSource.pixabay:
case WallpaperSource.haoWallpaper:
case WallpaperSource.bingEnhanced:
return true;
}
}
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';
}
// 仅对支持分类筛选的源传 category 参数
if (category != null &&
category != 'all' &&
supportsCategory) {
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;
}