import 'dart:async'; import 'package:flutter/material.dart'; import 'package:image_puzzle/audio/audio_controller.dart'; import 'package:image_puzzle/collection/grid_item.dart'; import 'package:image_puzzle/config/device.dart'; import 'package:image_puzzle/models/cached_request.dart'; import 'package:image_puzzle/models/data.dart'; import 'package:image_puzzle/models/items.dart'; import 'package:logging/logging.dart'; import 'package:lottie/lottie.dart'; import 'package:provider/provider.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 AudioController 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( appBar: AppBar( backgroundColor: Colors.white, elevation: 1, centerTitle: true, leading: IconButton( onPressed: () { audio.playSfx(SfxType.tap); Navigator.pop(context); }, icon: const Icon(Icons.arrow_back_outlined, color: Colors.black54), ), title: const Text( '收藏', style: TextStyle(color: Colors.black54, fontFamily: 'Arial Black', 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 _buildItem(context, index) { ListItem item = collection![index]; final bool isLocked = index >= data.currentCollectionIndex; // 假设 currentCollectionIndex 之前是解锁的 return Padding( padding: const EdgeInsets.all(10.0), child: GridItem(item: item, lock: false, index: index), ); } }