collection_screen.dart 4.7 KB

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