collection_screen.dart 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import 'dart:async';
  2. import 'package:flutter/material.dart';
  3. import 'package:puzzleweave/audio/jc_audio_controller.dart';
  4. import 'package:puzzleweave/collection/grid_item.dart';
  5. import 'package:puzzleweave/config/device.dart';
  6. import 'package:puzzleweave/l10n/app_localizations.dart';
  7. import 'package:puzzleweave/models/cached_request.dart';
  8. import 'package:puzzleweave/models/data.dart';
  9. import 'package:puzzleweave/models/items.dart';
  10. import 'package:logging/logging.dart';
  11. import 'package:lottie/lottie.dart';
  12. import 'package:provider/provider.dart';
  13. final Logger _log = Logger('collection_screen');
  14. class CollectionScreen extends StatefulWidget {
  15. const CollectionScreen({super.key});
  16. @override
  17. State<StatefulWidget> createState() => _CollectionScreen();
  18. static PageRouteBuilder buildRoute() {
  19. return PageRouteBuilder(
  20. pageBuilder: (context, animation, secondaryAnimation) {
  21. return CollectionScreen();
  22. },
  23. transitionsBuilder: (context, animation, secondaryAnimation, child) {
  24. // return FadeTransition(opacity: animation, child: child);
  25. return SlideTransition(
  26. position: Tween(begin: const Offset(1, 0), end: Offset.zero).animate(animation),
  27. child: child,
  28. );
  29. },
  30. );
  31. }
  32. }
  33. class _CollectionScreen extends State<CollectionScreen> {
  34. late JcAudioController audio;
  35. late Data data;
  36. List<ListItem>? collection;
  37. late CachedRequest collectionCachedRequest;
  38. late StreamSubscription? collectionSubscription;
  39. @override
  40. void initState() {
  41. super.initState();
  42. audio = context.read<JcAudioController>();
  43. data = context.read<Data>();
  44. collectionCachedRequest = data.collection;
  45. // 主动获取缓存数据(关键)
  46. final collectionCachedData = collectionCachedRequest.cachedData;
  47. if (collectionCachedData != null) {
  48. _onCollectionDataUpdate(collectionCachedData);
  49. }
  50. collectionSubscription = collectionCachedRequest.stream.listen(_onCollectionDataUpdate, onError: _onCollectionDataError);
  51. }
  52. @override
  53. void dispose() {
  54. collectionSubscription?.cancel();
  55. super.dispose();
  56. }
  57. _onCollectionDataUpdate(data) async {
  58. _log.info('_onCollectionDataUpdate.... ');
  59. if (data != null) {
  60. collection = data as List<ListItem>;
  61. setState(() {});
  62. }
  63. }
  64. _onCollectionDataError(error) {
  65. _log.info('_onCollectionDataError.... $error');
  66. }
  67. Future<void> refresh() async {
  68. _log.info('refresh...');
  69. await collectionCachedRequest.refresh();
  70. }
  71. @override
  72. Widget build(BuildContext context) {
  73. final device = context.read<Device>();
  74. final isTablet = device.isTablet;
  75. return Scaffold(
  76. appBar: AppBar(
  77. backgroundColor: Colors.white,
  78. elevation: 1,
  79. centerTitle: true,
  80. leading: IconButton(
  81. onPressed: () {
  82. audio.playSfx(SfxType.click);
  83. Navigator.pop(context);
  84. },
  85. icon: const Icon(Icons.arrow_back_outlined, color: Colors.black87),
  86. ),
  87. title: Text(
  88. AppLocalizations.of(context)!.collection,
  89. style: TextStyle(color: Colors.black87, fontWeight: FontWeight.bold, fontSize: 24),
  90. ),
  91. ),
  92. body: collection == null
  93. ? scrollableDummy
  94. : RefreshIndicator(
  95. onRefresh: refresh,
  96. child: CustomScrollView(
  97. slivers: <Widget>[
  98. // header
  99. SliverPadding(
  100. sliver: SliverGrid(
  101. gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(maxCrossAxisExtent: isTablet ? 300 : 210, childAspectRatio: 2 / 3),
  102. delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
  103. return _buildItem(context, index);
  104. }, childCount: collection!.length),
  105. ),
  106. padding: const EdgeInsets.only(left: 10.0, right: 10.0),
  107. ),
  108. ],
  109. ),
  110. ),
  111. );
  112. }
  113. Widget get scrollableDummy => LayoutBuilder(
  114. builder: (p0, p1) {
  115. return SingleChildScrollView(
  116. physics: const AlwaysScrollableScrollPhysics(),
  117. child: SizedBox(
  118. height: p1.maxHeight,
  119. child: Center(
  120. child: ListView(
  121. shrinkWrap: true,
  122. children: [
  123. Lottie.asset('assets/lottie/loading.json', height: 100),
  124. const Center(child: Text("loading...")),
  125. ],
  126. ),
  127. ),
  128. ),
  129. );
  130. },
  131. );
  132. Widget _buildItem(context, index) {
  133. ListItem item = collection![index];
  134. final bool isLocked = index >= data.currentCollectionIndex; // 假设 currentCollectionIndex 之前是解锁的
  135. return Padding(
  136. padding: const EdgeInsets.all(10.0),
  137. child: GridItem(item: item, lock: isLocked, index: index),
  138. );
  139. }
  140. }