// 贴纸 BLoC — 通过 API 加载贴纸包和贴纸数据 import 'package:flutter/material.dart'; import 'package:nuanji_app/data/remote/api_client.dart'; // ===== 模型 ===== /// 贴纸包 class StickerPack { final String id; final String name; final String? description; final String? coverImageUrl; final int stickerCount; final bool isFree; final String? category; const StickerPack({ required this.id, required this.name, this.description, this.coverImageUrl, this.stickerCount = 0, this.isFree = true, this.category, }); /// 兼容旧 UI 的 emoji 封面(优先用 coverImageUrl,否则用默认) String get displayCover => coverImageUrl ?? '🎨'; } /// 单张贴纸 class Sticker { final String id; final String packId; final String name; final String imageUrl; final String? category; const Sticker({ required this.id, required this.packId, required this.name, required this.imageUrl, this.category, }); } // ===== State ===== /// 贴纸页面状态 class StickerState { final List packs; final String selectedCategory; final bool isLoading; final String? errorMessage; const StickerState({ this.packs = const [], this.selectedCategory = '全部', this.isLoading = false, this.errorMessage, }); /// 按分类过滤贴纸包 List get filteredPacks => selectedCategory == '全部' ? packs : packs.where((p) => p.category == selectedCategory).toList(); /// 所有分类(去重 + 加"全部") List get categories { final cats = packs .map((p) => p.category) .whereType() .toSet() .toList(); return ['全部', ...cats]; } StickerState copyWith({ List? packs, String? selectedCategory, bool? isLoading, String? errorMessage, }) => StickerState( packs: packs ?? this.packs, selectedCategory: selectedCategory ?? this.selectedCategory, isLoading: isLoading ?? this.isLoading, errorMessage: errorMessage, ); } // ===== BLoC ===== /// 贴纸 BLoC — ChangeNotifier 模式 class StickerBloc extends ChangeNotifier { final ApiClient _api; StickerState _state = const StickerState(); StickerState get state => _state; StickerBloc({required ApiClient api}) : _api = api; /// 加载贴纸包列表 void load() { _state = _state.copyWith(isLoading: true); notifyListeners(); _fetchPacks(); } /// 选择分类 void selectCategory(String category) { _state = _state.copyWith(selectedCategory: category); notifyListeners(); } /// 按分类加载贴纸包 void loadByCategory(String? category) { _state = _state.copyWith(isLoading: true); notifyListeners(); _fetchPacks(category: category); } Future _fetchPacks({String? category}) async { try { final queryParams = category != null && category != '全部' ? {'category': category} : null; final response = await _api.get( '/diary/sticker-packs', queryParams: queryParams, ); final body = response.data as Map; final list = body['data'] as List? ?? []; final packs = list.map((item) { final m = item as Map; return StickerPack( id: m['id'] as String, name: m['name'] as String, description: m['description'] as String?, coverImageUrl: m['cover_image_url'] as String?, stickerCount: (m['sticker_count'] as num?)?.toInt() ?? 0, isFree: m['is_free'] as bool? ?? true, category: m['category'] as String?, ); }).toList(); _state = _state.copyWith(isLoading: false, packs: packs); } catch (e) { _state = _state.copyWith( isLoading: false, errorMessage: '加载贴纸包失败', ); } notifyListeners(); } /// 获取贴纸包内的贴纸列表 Future> fetchStickersInPack(String packId) async { try { final response = await _api.get('/diary/sticker-packs/$packId/stickers'); final body = response.data as Map; final list = body['data'] as List? ?? []; return list.map((item) { final m = item as Map; return Sticker( id: m['id'] as String, packId: m['pack_id'] as String, name: m['name'] as String, imageUrl: m['image_url'] as String, category: m['category'] as String?, ); }).toList(); } catch (e) { return []; } } }