import 'dart:async'; import 'package:flutter/material.dart'; import 'package:puzzleweave/audio/jc_audio_controller.dart'; import 'package:puzzleweave/collection/grid_item.dart'; import 'package:puzzleweave/config/device.dart'; import 'package:puzzleweave/l10n/app_localizations.dart'; import 'package:puzzleweave/models/cached_request.dart'; import 'package:puzzleweave/models/data.dart'; import 'package:puzzleweave/models/items.dart'; import 'package:logging/logging.dart'; import 'package:lottie/lottie.dart'; import 'package:provider/provider.dart'; import 'package:puzzleweave/skin/skin.dart'; final Logger _log = Logger('collection_screen'); class CollectionScreen extends StatefulWidget { const CollectionScreen({super.key}); @override State createState() => _CollectionScreen(); static PageRouteBuilder buildRoute() { return PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) { return CollectionScreen(); }, transitionsBuilder: (context, animation, secondaryAnimation, child) { // return FadeTransition(opacity: animation, child: child); return SlideTransition( position: Tween(begin: const Offset(1, 0), end: Offset.zero).animate(animation), child: child, ); }, ); } } class _CollectionScreen extends State { late JcAudioController audio; late Data data; List? collection; late CachedRequest collectionCachedRequest; late StreamSubscription? collectionSubscription; @override void initState() { super.initState(); audio = context.read(); data = context.read(); collectionCachedRequest = data.collection; // 主动获取缓存数据(关键) final collectionCachedData = collectionCachedRequest.cachedData; if (collectionCachedData != null) { _onCollectionDataUpdate(collectionCachedData); } collectionSubscription = collectionCachedRequest.stream.listen(_onCollectionDataUpdate, onError: _onCollectionDataError); } @override void dispose() { collectionSubscription?.cancel(); super.dispose(); } _onCollectionDataUpdate(data) async { _log.info('_onCollectionDataUpdate.... '); if (data != null) { collection = data as List; setState(() {}); } } _onCollectionDataError(error) { _log.info('_onCollectionDataError.... $error'); } Future refresh() async { _log.info('refresh...'); await collectionCachedRequest.refresh(); } @override Widget build(BuildContext context) { final device = context.read(); final isTablet = device.isTablet; return Scaffold( backgroundColor: SkinHelper.colorWhite, appBar: AppBar( backgroundColor: SkinHelper.colorWhite, // elevation: 1, centerTitle: true, leading: IconButton( onPressed: () { audio.playSfx(SfxType.click); Navigator.pop(context); }, icon: const Icon(Icons.arrow_back_outlined, color: Colors.black87), ), title: Text( AppLocalizations.of(context)!.collection, style: TextStyle(color: Colors.black87, fontWeight: FontWeight.bold, fontSize: 24), ), ), body: collection == null ? scrollableDummy : RefreshIndicator( onRefresh: refresh, child: CustomScrollView( slivers: [ // header SliverPadding( sliver: SliverGrid( gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(maxCrossAxisExtent: isTablet ? 300 : 210, childAspectRatio: 2 / 3), delegate: SliverChildBuilderDelegate((BuildContext context, int index) { return _buildItem(context, index); }, childCount: collection!.length), ), padding: const EdgeInsets.only(left: 10.0, right: 10.0), ), ], ), ), ); } // Widget get scrollableDummy => LayoutBuilder( // builder: (p0, p1) { // return SingleChildScrollView( // physics: const AlwaysScrollableScrollPhysics(), // child: SizedBox( // height: p1.maxHeight, // child: Center( // child: ListView( // shrinkWrap: true, // children: [ // Lottie.asset('assets/lottie/loading.json', height: 100), // const Center(child: Text("loading...")), // ], // ), // ), // ), // ); // }, // ); Widget get scrollableDummy => Scaffold( backgroundColor: SkinHelper.colorWhite, body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 替换 Lottie 为原生进度条 SizedBox(width: 40, height: 40, child: CircularProgressIndicator(strokeWidth: 3, valueColor: AlwaysStoppedAnimation(SkinHelper.coreBgColor))), const SizedBox(height: 16), Text( "Loading...", style: TextStyle(color: SkinHelper.slotBorderColor.withOpacity(0.7), fontSize: 14, fontWeight: FontWeight.w500), ), ], ), ), ); Widget _buildItem(context, index) { ListItem item = collection![index]; final bool isLocked = index >= data.currentCollectionIndex; // 假设 currentCollectionIndex 之前是解锁的 return Padding( padding: const EdgeInsets.all(10.0), child: CollectionGridItem(item: item, lock: isLocked, index: index), ); } }