| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- import 'dart:async';
- import 'package:flutter/material.dart';
- import 'package:fluttertoast/fluttertoast.dart';
- import 'package:image_puzzle/audio/audio_controller.dart';
- import 'package:image_puzzle/collection/collection_screen.dart';
- import 'package:image_puzzle/config/device.dart';
- import 'package:image_puzzle/homepage/home_board.dart';
- import 'package:image_puzzle/homepage/home_board_play.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:image_puzzle/play/board_play.dart';
- import 'package:image_puzzle/settings/settings_dialog.dart';
- import 'package:image_puzzle/skin/skin.dart';
- import 'package:image_puzzle/utils/mybutton.dart';
- import 'package:logging/logging.dart';
- import 'package:lottie/lottie.dart';
- import 'package:provider/provider.dart';
- final Logger _log = Logger('home_screen');
- class HomeScreen extends StatefulWidget {
- const HomeScreen({super.key});
- @override
- State<StatefulWidget> createState() => _HomeScreen();
- }
- class _HomeScreen extends State<HomeScreen> {
- late AudioController audio;
- late Data data;
- List<ListItem>? latest;
- late CachedRequest latestCachedRequest;
- late StreamSubscription? latestSubscription;
- // 自定义画布控制器(可选,用于控制画布绘制逻辑)
- final _canvasKey = GlobalKey<HomeBoardPlayState>();
- // !!! 新增:用于定位 Collection 按钮的 GlobalKey
- final GlobalKey _collectionKey = GlobalKey();
- bool get isLoading => currentItem == null;
- @override
- void initState() {
- super.initState();
- audio = context.read<AudioController>();
- data = context.read<Data>();
- latestCachedRequest = data.latest;
- // 主动获取缓存数据(关键)
- final cachedData = latestCachedRequest.cachedData;
- if (cachedData != null) {
- _onLatestDataUpdate(cachedData);
- }
- latestSubscription = latestCachedRequest.stream.listen(_onLatestDataUpdate, onError: _onLatestDataError);
- }
- @override
- void dispose() {
- latestSubscription?.cancel();
- super.dispose();
- }
- _onLatestDataUpdate(data) {
- _log.info('_onLatestDataUpdate.... ');
- if (data != null) {
- latest = data as List<ListItem>;
- setState(() {});
- if (data.length >= 20) {
- // 远程latest列表已加载,说明网络已通,这个时候再来初始化Admod,ATT, UMP这些东西
- initThird();
- }
- }
- }
- _onLatestDataError(error) {
- _log.info('_onLatestDataError.... $error');
- if (latest == null || latest!.isEmpty || latest!.length < 20) {
- // 列表数据如果少于20,说明只是内置图,仍然刷新远程请求
- _log.warning("_onLatestDataError, retry again");
- // refresh();
- Future.delayed(Duration(seconds: 3), () => refresh());
- }
- }
- Future<void> refresh() async {
- _log.info('refresh...');
- await latestCachedRequest.refresh();
- }
- void initThird() async {}
- ListItem? get currentItem {
- if (latest != null && latest!.isNotEmpty) {
- return latest![data.currentLevel];
- }
- return null;
- }
- @override
- Widget build(BuildContext context) {
- if (isLoading) return scrollableDummy;
- Device device = context.read<Device>();
- // 2. 计算画布尺寸(宽=屏幕宽-60,高=宽×3/2)
- final canvasWidth = device.screenSize.width - 30 * 2; // 左右各30px
- final canvasHeight = canvasWidth * 3 / 2;
- return Scaffold(
- appBar: AppBar(
- backgroundColor: Colors.white,
- elevation: 1,
- centerTitle: true,
- leading: RepaintBoundary(
- // !!! 改造点 1: 包裹 RepaintBoundary
- key: _collectionKey, // !!! 改造点 2: 关联 GlobalKey
- child: IconButton(
- onPressed: () {
- audio.playSfx(SfxType.tap);
- Navigator.push(context, CollectionScreen.buildRoute());
- },
- icon: const Icon(Icons.collections, color: Colors.black54),
- ),
- ),
- title: const Text(
- 'PuzzleWeave',
- style: TextStyle(color: Colors.black54, fontFamily: 'Arial Black', fontWeight: FontWeight.bold, fontSize: 24),
- ),
- actions: [
- IconButton(
- onPressed: () {
- audio.playSfx(SfxType.tap);
- Navigator.push(context, SettingsDialog.buildRoute());
- },
- icon: const Icon(Icons.settings, color: Colors.black54),
- ),
- ],
- ),
- body: Column(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Expanded(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- // 2. 画布区域(固定尺寸)
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 30), // 左右30px
- child: SizedBox(
- width: canvasWidth,
- height: canvasHeight,
- child: ValueListenableBuilder(
- valueListenable: data.completedWorks,
- builder: (context, value, child) {
- return HomeBoardPlay(
- key: _canvasKey,
- canvasWidth: canvasWidth,
- canvasHeight: canvasHeight,
- collectionKey: _collectionKey,
- onCollectionDone: () {
- // 可选:在这里处理合集解锁后的其他逻辑
- },
- );
- },
- ),
- ),
- ),
- playButton,
- ],
- ),
- ),
- Container(
- height: device.bannerHeight,
- width: double.infinity,
- color: Colors.green.shade100,
- child: const Center(child: Text('Banner 广告区域', style: TextStyle(fontSize: 12))),
- ),
- ],
- ),
- );
- }
- Widget get playButton {
- return MyElevatedButton(
- width: 200,
- height: 70,
- borderRadius: BorderRadius.circular(20),
- gradient: LinearGradient(colors: [SkinHelper.coreBgColor, SkinHelper.slotBorderColor]),
- onPressed: () async {
- audio.playSfx(SfxType.tap);
- _canvasKey.currentState?.startFlipAnimation();
- // if (currentItem != null) {
- // PageRouteBuilder? pageRouteBuilder = BoardPlay.buildRoute(currentItem!);
- // final result = await Navigator.push(context, pageRouteBuilder);
- // if (result == true) {
- // _canvasKey.currentState?.startFlipAnimation();
- // }
- // } else {
- // Fluttertoast.showToast(
- // msg: "更多图片敬请期待...",
- // toastLength: Toast.LENGTH_SHORT,
- // gravity: ToastGravity.CENTER,
- // timeInSecForIosWeb: 1,
- // backgroundColor: SkinHelper.slotBorderColor,
- // textColor: Colors.white,
- // fontSize: 16.0,
- // );
- // }
- },
- child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- const Text(
- '玩',
- style: TextStyle(color: Colors.white, fontFamily: 'Arial Black', fontSize: 24, fontWeight: FontWeight.bold),
- ),
- ValueListenableBuilder<List<Work>>(
- valueListenable: data.completedWorks,
- builder: (context, isSoundOn, child) {
- return Text('关卡 ${data.currentLevel + 1}', style: const TextStyle(color: Colors.white, fontSize: 16));
- },
- ),
- ],
- ),
- );
- }
- Widget get scrollableDummy => Scaffold(
- body: 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)])),
- ),
- );
- },
- ),
- );
- }
|