Kaynağa Gözat

feat(home): add home page

zhaoyadi 11 ay önce
ebeveyn
işleme
5479a8e49c

+ 1 - 3
android/app/src/main/AndroidManifest.xml

@@ -1,13 +1,11 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android">
     <application
-        android:label="battle"
-        android:name="${applicationName}"
+        android:label="逻辑狗AI对抗"
         android:icon="@mipmap/ic_launcher">
         <activity
             android:name=".MainActivity"
             android:exported="true"
             android:launchMode="singleTop"
-            android:taskAffinity=""
             android:theme="@style/LaunchTheme"
             android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
             android:hardwareAccelerated="true"

BIN
assets/cards/chs2-14.jpg


BIN
assets/cards/chs2-16.jpg


BIN
assets/cards/chs2-6.jpg


BIN
assets/cards/cms2-1.jpg


BIN
assets/cards/cms2-15.jpg


BIN
assets/cards/cms2-5.jpg


BIN
assets/cards/css2-11.jpg


BIN
assets/cards/css2-13.jpg


BIN
assets/cards/css2-2.jpg


BIN
assets/images/background.png


BIN
assets/images/test.jpg


+ 19 - 9
lib/app/battle_app.dart

@@ -1,19 +1,29 @@
+import 'package:battle/route.dart';
 import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:go_router/go_router.dart';
 
-import '../page/game_page.dart';
-
-class BattleApp extends StatelessWidget {
+class BattleApp extends StatefulWidget {
   const BattleApp({super.key});
 
+  @override
+  State<BattleApp> createState() => _BattleAppState();
+}
+
+class _BattleAppState extends State<BattleApp> {
+  final GoRouter _router = GoRouter(routes: $appRoutes);
+
   @override
   Widget build(BuildContext context) {
-    return MaterialApp(
-      title: '逻辑狗AI对抗',
-      theme: ThemeData(
-        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
-        useMaterial3: true,
+    return ProviderScope(
+      child: MaterialApp.router(
+        title: '逻辑狗AI对抗',
+        routerConfig: _router,
+        theme: ThemeData(
+          useMaterial3: true,
+          colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
+        ),
       ),
-      home: const GamePage(),
     );
   }
 }

+ 3 - 3
lib/button/button_color.dart

@@ -1,10 +1,10 @@
 import 'dart:ui';
 
-List<Color> colors = <Color>[
+List<Color> buttonColors = <Color>[
   const Color(0xFFFF0000),
+  const Color(0xFFFF7700),
+  const Color(0xFFFFFF00),
   const Color(0xFF00FF00),
   const Color(0xFF0000FF),
-  const Color(0xFFFFFF00),
-  const Color(0xFF00FFFF),
   const Color(0xFFFF00FF),
 ];

+ 45 - 63
lib/button/button_controller.dart

@@ -1,10 +1,8 @@
-import 'dart:math';
-
 import 'package:battle/button/button_color.dart';
-import 'package:flutter/animation.dart';
-import 'package:flutter/foundation.dart';
+import 'package:battle/data/card.dart';
+import 'package:flutter/cupertino.dart';
 
-import '../data/data.dart';
+import '../utils/utils.dart';
 
 enum ButtonState { start, stop }
 
@@ -14,100 +12,84 @@ class ButtonInfo {
   int endIndex;
   double process;
 
+  /// 是否执行超出回退动画
+  bool overflow;
+
+  /// 是否执行卡住动画
+  bool pauseBottom;
+
+  bool pauseInline;
+
+  bool pauseRight;
+
   ButtonInfo({
     required this.color,
     required this.startIndex,
     required this.endIndex,
     this.process = 0,
+    this.overflow = false,
+    this.pauseBottom = false,
+    this.pauseInline = false,
+    this.pauseRight = false,
   });
 }
 
+/// 四步完成随机性
+/// 1. 根据答案编排出按钮颜色的最终位置
+/// 2. 随机生成初始位置数组并赋值给按钮
+/// 3. 打乱按钮顺序即调整按钮的起始位置
+/// 4. 随机生成按钮出发顺序并赋值给动画
 class ButtonController with ChangeNotifier {
+  final CardItem cardItem;
   final TickerProvider vsync;
 
-  ButtonController({required this.vsync}) {
+  ButtonController(this.cardItem, {required this.vsync}) {
     _animationController = AnimationController(
       upperBound: 6.0,
       vsync: vsync,
-      duration: Duration(seconds: 10),
+      duration: const Duration(seconds: 30),
     );
 
-    List<Color> colorList = _generateColorList();
-    List<int> startIndex = _generateIntList();
-    List<int> endIndex = _generateIntList();
-
-    startButton = List.generate(6, (index) {
-      return ButtonInfo(
-        color: colorList[index],
-        startIndex: startIndex[index],
-        endIndex: endIndex[index],
-      );
-    });
+    _randomButton();
 
     _animationController.addListener(() {
       int index = _animationController.value ~/ 1;
       double process = _animationController.value % 1.0;
 
-      startButton[index].process = process;
-
+      buttonList[_moveIndex[index]].process = Curves.easeInOutQuint.transform(process);
       notifyListeners();
     });
   }
 
-  void start() {
-    _animationController.forward();
-  }
+  late AnimationController _animationController;
+  late List<ButtonInfo> buttonList = [];
+  late List<int> _moveIndex = [];
+
+  void _randomButton() {
+    _moveIndex = generateIntList();
+    List<int> startIndex = generateIntList();
 
-  void reset() {
-    List<Color> colorList = _generateColorList();
-    List<int> startIndex = _generateIntList();
-    List<int> endIndex = _generateIntList();
+    buttonList = List.generate(6, (index) {
+      final answer = cardItem.answer[index] - 1;
 
-    startButton = List.generate(6, (index) {
       return ButtonInfo(
-        color: colorList[index],
+        color: buttonColors[answer],
         startIndex: startIndex[index],
-        endIndex: endIndex[index],
+        endIndex: index,
       );
     });
-
-    _animationController.forward(from: 0);
   }
 
-  void stop() {
-    _animationController.stop();
-  }
+  bool get isRunning => _animationController.isAnimating;
 
-  late AnimationController _animationController;
-  late List<ButtonInfo> startButton = [];
-
-  List<Color> _generateColorList() {
-    List<Color> list = List.of(colors);
-    var random = Random.secure();
-    for (int i = 0; i < 10; i++) {
-      int i = random.nextInt(list.length);
-      int j = random.nextInt(list.length);
-
-      Color temp = list[i];
-      list[i] = list[j];
-      list[j] = temp;
+  void startOrReset() {
+    if (_animationController.isAnimating) {
+      _randomButton();
     }
-
-    return list;
+    _animationController.forward(from: 0);
   }
 
-  List<int> _generateIntList() {
-    List<int> list = answers[0].toList();
-    var random = Random.secure();
-    for (int i = 0; i < 3; i++) {
-      int i = random.nextInt(list.length);
-      int j = random.nextInt(list.length);
-
-      int temp = list[i];
-      list[i] = list[j];
-      list[j] = temp;
-    }
-
-    return list;
+  void stop() {
+    _animationController.stop();
   }
 }

+ 1 - 1
lib/button/button_painter.dart

@@ -15,7 +15,7 @@ class ButtonPainter extends CustomPainter {
       ..style = PaintingStyle.fill
       ..strokeWidth = 4;
 
-    for (var button in controller.startButton) {
+    for (var button in controller.buttonList) {
       var path = fromBottomToCenter(size, button.startIndex, button.endIndex);
       var pms = path.computeMetrics();
       for (var pm in pms) {

+ 65 - 0
lib/data/card.dart

@@ -0,0 +1,65 @@
+class CardItem {
+  final String cardName;
+  final String assetPath;
+  final List<int> answer;
+
+  CardItem({
+    required this.cardName,
+    required this.assetPath,
+    required this.answer,
+  });
+}
+
+final List<CardItem> smallCardList = <CardItem>[
+  CardItem(
+    cardName: '和大自然一起玩-2',
+    assetPath: 'assets/cards/css2-2.jpg',
+    answer: [4, 5, 3, 1, 2, 6],
+  ),
+  CardItem(
+    cardName: '我会穿衣服-11',
+    assetPath: 'assets/cards/css2-11.jpg',
+    answer: [5, 4, 3, 1, 6, 2],
+  ),
+  CardItem(
+    cardName: '美食总动员-13',
+    assetPath: 'assets/cards/css2-13.jpg',
+    answer: [2, 4, 1, 6, 3, 5],
+  ),
+];
+
+final List<CardItem> middleCardList = <CardItem>[
+  CardItem(
+    cardName: '一起捉迷藏-1',
+    assetPath: 'assets/cards/cms2-1.jpg',
+    answer: [2, 5, 1, 6, 4, 3],
+  ),
+  CardItem(
+    cardName: '繁忙的交通-5',
+    assetPath: 'assets/cards/cms2-5.jpg',
+    answer: [3, 4, 5, 2, 1, 6],
+  ),
+  CardItem(
+    cardName: '繁忙的交通-15',
+    assetPath: 'assets/cards/cms2-15.jpg',
+    answer: [4, 5, 3, 2, 6, 1],
+  ),
+];
+
+final List<CardItem> seniorCardList = <CardItem>[
+  CardItem(
+    cardName: '热闹的跳蚤市场-6',
+    assetPath: 'assets/cards/chs2-6.jpg',
+    answer: [1, 2, 6, 3, 5, 4],
+  ),
+  CardItem(
+    cardName: '热闹的跳蚤市场-14',
+    assetPath: 'assets/cards/chs2-14.jpg',
+    answer: [6, 2, 4, 5, 1, 3],
+  ),
+  CardItem(
+    cardName: '热闹的跳蚤市场-16',
+    assetPath: 'assets/cards/chs2-16.jpg',
+    answer: [1, 2, 4, 6, 3, 5],
+  ),
+];

+ 0 - 9
lib/data/data.dart

@@ -1,9 +0,0 @@
-final List<(int, int, int, int, int, int)> answers = [
-  (4, 3, 2, 5, 1, 0),
-];
-
-extension AnswerToList on (int, int, int, int, int, int) {
-  List<int> toList() {
-    return [$1, $2, $3, $4, $5, $6];
-  }
-}

+ 28 - 0
lib/page/about_page.dart

@@ -0,0 +1,28 @@
+import 'package:flutter/material.dart';
+
+class AboutPage extends StatefulWidget {
+  const AboutPage({super.key});
+
+  @override
+  State<AboutPage> createState() => _AboutPageState();
+}
+
+class _AboutPageState extends State<AboutPage> {
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(title: const Text('关于')),
+      body: const SingleChildScrollView(
+        child: Column(
+          children: [
+            ListTile(
+              leading: Icon(Icons.info_outline_rounded),
+              title: Text('开源许可'),
+              trailing: Icon(Icons.arrow_forward_ios_rounded),
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}

+ 123 - 34
lib/page/game_page.dart

@@ -1,11 +1,20 @@
+import 'dart:async';
+
 import 'package:battle/button/button_controller.dart';
+import 'package:battle/data/card.dart';
 import 'package:flutter/material.dart';
 import 'package:widget/widget.dart';
 
 import '../button/button_painter.dart';
+import 'setting_page.dart';
 
 class GamePage extends StatefulWidget {
-  const GamePage({super.key});
+  final CardItem card;
+
+  const GamePage({
+    super.key,
+    required this.card,
+  });
 
   @override
   State<GamePage> createState() => _GamePageState();
@@ -13,16 +22,25 @@ class GamePage extends StatefulWidget {
 
 class _GamePageState extends State<GamePage> with SingleTickerProviderStateMixin {
   late ButtonController _controller;
+  Timer? _timer;
+
+  int _count = 0;
 
   @override
   void initState() {
     super.initState();
-    _controller = ButtonController(vsync: this);
-    _controller.start();
+    _controller = ButtonController(widget.card, vsync: this);
   }
 
-  void _reset() {
-    _controller.reset();
+  void _createTimer() {
+    _timer?.cancel();
+    _timer = Timer.periodic(const Duration(milliseconds: 250), (count) {
+      if (mounted) {
+        setState(() {
+          _count = count.tick;
+        });
+      }
+    });
   }
 
   @override
@@ -33,46 +51,117 @@ class _GamePageState extends State<GamePage> with SingleTickerProviderStateMixin
           Positioned.fill(
             child: ColorFiltered(
               colorFilter: const ColorFilter.matrix(<double>[
-                1, 0, 0, 0, 0, //r
-                0, 1, 0, 0, 0, //r
-                0, 0, 1, 0, 0, //r
-                0, 0, 0, 0.25, 0, //r
+                0.299, 0.587, 0.114, 0, 0, //r
+                0.299, 0.587, 0.114, 0, 0, //g
+                0.299, 0.587, 0.114, 0, 0, //b
+                0, 0, 0, 0.1, 0, //a
               ]),
               child: Image.asset(
                 'assets/images/background.png',
                 repeat: ImageRepeat.repeat,
-                cacheWidth: 30,
-                cacheHeight: 30,
+                cacheWidth: 182,
+                cacheHeight: 52,
               ),
             ),
           ),
           Positioned.fill(
-            child: Column(
-              children: [
-                Expanded(
-                  child: Padding(
-                    padding: const EdgeInsets.symmetric(horizontal: 16),
-                    child: BattleBoard(
-                      card: ClipRRect(
-                        borderRadius: BorderRadius.circular(8),
-                        child: Container(
-                          color: Colors.grey,
+            child: SafeArea(
+              top: true,
+              bottom: true,
+              child: Column(
+                children: [
+                  Expanded(
+                    child: Column(
+                      mainAxisSize: MainAxisSize.min,
+                      mainAxisAlignment: MainAxisAlignment.center,
+                      children: [
+                        Padding(
+                          padding: const EdgeInsets.symmetric(horizontal: 16),
+                          child: Align(
+                            alignment: Alignment.centerLeft,
+                            child: Container(
+                              padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
+                              decoration: BoxDecoration(
+                                borderRadius: BorderRadius.circular(40),
+                                color: Theme.of(context).colorScheme.primaryContainer,
+                              ),
+                              child: Row(
+                                mainAxisSize: MainAxisSize.min,
+                                children: [
+                                  const Icon(Icons.timer),
+                                  const SizedBox(width: 8),
+                                  Text(
+                                    '${Duration(milliseconds: _count * 250).inSeconds}秒',
+                                    style: Theme.of(context).textTheme.titleLarge,
+                                  ),
+                                  const SizedBox(width: 8),
+                                ],
+                              ),
+                            ),
+                          ),
+                        ),
+                        const SizedBox(height: 16),
+                        Padding(
+                          padding: const EdgeInsets.symmetric(horizontal: 16),
+                          child: BattleBoard(
+                            card: ClipRRect(
+                              borderRadius: BorderRadius.circular(8),
+                              child: Container(
+                                width: double.infinity,
+                                height: double.infinity,
+                                color: Colors.grey,
+                                child: Image.asset(
+                                  widget.card.assetPath,
+                                  fit: BoxFit.cover,
+                                ),
+                              ),
+                            ),
+                            button: CustomPaint(
+                              painter: ButtonPainter(controller: _controller),
+                              child: const SizedBox.expand(),
+                            ),
+                          ),
                         ),
-                      ),
-                      button: CustomPaint(
-                        painter: ButtonPainter(controller: _controller),
-                        child: const SizedBox.expand(),
-                      ),
+                        SizedBox(height: 32),
+                        Padding(
+                          padding: const EdgeInsets.symmetric(horizontal: 16),
+                          child: ButtonBar(
+                            alignment: MainAxisAlignment.spaceAround,
+                            children: [
+                              FilledButton(
+                                onPressed: () {
+                                  _createTimer();
+                                  _controller.startOrReset();
+                                },
+                                child: const Text('开始'),
+                              ),
+                              FilledButton(
+                                onPressed: () {
+                                  _controller.stop();
+                                  _timer?.cancel();
+                                },
+                                child: const Text('停止'),
+                              ),
+                            ],
+                          ),
+                        ),
+                      ],
                     ),
                   ),
-                ),
-                TextButton(
-                  onPressed: () {
-                    _reset();
-                  },
-                  child: const Text('重新开始'),
-                ),
-              ],
+                ],
+              ),
+            ),
+          ),
+          Positioned(
+            right: 16,
+            top: MediaQuery.of(context).padding.top + 16,
+            child: IconButton(
+              icon: const Icon(Icons.settings),
+              onPressed: () {
+                Navigator.push(context, MaterialPageRoute(builder: (_) {
+                  return const SettingPage();
+                }));
+              },
             ),
           ),
         ],

+ 95 - 27
lib/page/home_page.dart

@@ -1,50 +1,118 @@
-
+import 'package:battle/route.dart';
 import 'package:flutter/material.dart';
 
-class MyHomePage extends StatefulWidget {
-  const MyHomePage({super.key, required this.title});
+import '../data/card.dart';
 
-  final String title;
+class HomePage extends StatefulWidget {
+  const HomePage({super.key});
 
   @override
-  State<MyHomePage> createState() => _MyHomePageState();
+  State<HomePage> createState() => _HomePageState();
 }
 
-class _MyHomePageState extends State<MyHomePage> {
-  int _counter = 0;
+class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
+  late TabController _tabController;
 
-  void _incrementCounter() {
-    setState(() {
-      _counter++;
-    });
+  @override
+  void initState() {
+    super.initState();
+    _tabController = TabController(length: 3, vsync: this);
+  }
+
+  @override
+  void dispose() {
+    _tabController.dispose();
+    super.dispose();
   }
 
   @override
   Widget build(BuildContext context) {
     return Scaffold(
       appBar: AppBar(
-        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
-        title: Text(widget.title),
+        title: Text(
+          '逻辑狗AI对抗',
+          style: TextStyle(color: Theme.of(context).colorScheme.primary),
+        ),
+        centerTitle: true,
+        backgroundColor: Theme.of(context).colorScheme.surface,
       ),
-      body: Center(
-        child: Column(
-          mainAxisAlignment: MainAxisAlignment.center,
-          children: <Widget>[
-            const Text(
-              'You have pushed the button this many times:',
+      body: Column(
+        children: [
+          SizedBox(
+            width: double.infinity,
+            height: 64,
+            child: TabBar(
+              controller: _tabController,
+              tabs: const [
+                Tab(text: '小班下'),
+                Tab(text: '中班下'),
+                Tab(text: '大班下'),
+              ],
             ),
-            Text(
-              '$_counter',
-              style: Theme.of(context).textTheme.headlineMedium,
+          ),
+          const SizedBox(height: 16),
+          Expanded(
+            child: TabBarView(
+              controller: _tabController,
+              children: [
+                GridView.count(
+                  crossAxisCount: 2,
+                  mainAxisSpacing: 8.0,
+                  crossAxisSpacing: 8.0,
+                  padding: const EdgeInsets.symmetric(horizontal: 16),
+                  childAspectRatio: 1 / 1.6,
+                  children: smallCardList.map(_buildCard).toList(),
+                ),
+                GridView.count(
+                  crossAxisCount: 2,
+                  mainAxisSpacing: 8.0,
+                  crossAxisSpacing: 8.0,
+                  padding: const EdgeInsets.symmetric(horizontal: 16),
+                  childAspectRatio: 1 / 1.6,
+                  children: middleCardList.map(_buildCard).toList(),
+                ),
+                GridView.count(
+                  crossAxisCount: 2,
+                  mainAxisSpacing: 8.0,
+                  crossAxisSpacing: 8.0,
+                  padding: const EdgeInsets.symmetric(horizontal: 16),
+                  childAspectRatio: 1 / 1.6,
+                  children: seniorCardList.map(_buildCard).toList(),
+                ),
+              ],
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+
+  Widget _buildCard(CardItem card) {
+    return GestureDetector(
+      onTap: () => GameRouter(
+        cardName: card.cardName,
+        assetPath: card.assetPath,
+        answer: card.answer,
+      ).push(context),
+      child: Card(
+        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
+        clipBehavior: Clip.antiAlias,
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            Image.asset(card.assetPath),
+            Expanded(
+              child: Align(
+                alignment: Alignment.centerLeft,
+                child: Padding(
+                  padding: const EdgeInsets.symmetric(horizontal: 8.0),
+                  child: Text(card.cardName),
+                ),
+              ),
             ),
           ],
         ),
       ),
-      floatingActionButton: FloatingActionButton(
-        onPressed: _incrementCounter,
-        tooltip: 'Increment',
-        child: const Icon(Icons.add),
-      ),
     );
   }
 }

+ 32 - 0
lib/page/setting_page.dart

@@ -0,0 +1,32 @@
+import 'package:flutter/material.dart';
+
+class SettingPage extends StatefulWidget {
+  const SettingPage({super.key});
+
+  @override
+  State<SettingPage> createState() => _SettingPageState();
+}
+
+class _SettingPageState extends State<SettingPage> {
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(title: const Text('设置')),
+      body: const SingleChildScrollView(
+        child:Column(
+          children: [
+            SizedBox(
+              width: double.infinity,
+              height: 48,
+              child: Row(
+                children: [
+                  Icon(Icons.brightness_medium_outlined)
+                ],
+              ),
+            )
+          ],
+        ),
+      ),
+    );
+  }
+}

+ 58 - 0
lib/route.dart

@@ -0,0 +1,58 @@
+import 'package:flutter/material.dart';
+import 'package:go_router/go_router.dart';
+
+import 'data/card.dart';
+import 'page/about_page.dart';
+import 'page/game_page.dart';
+import 'page/home_page.dart';
+import 'page/setting_page.dart';
+
+part 'route.g.dart';
+
+@TypedGoRoute<HomeRoute>(path: '/')
+class HomeRoute extends GoRouteData {
+  @override
+  Widget build(BuildContext context, GoRouterState state) {
+    return const HomePage();
+  }
+}
+
+@TypedGoRoute<SettingRoute>(path: '/setting')
+class SettingRoute extends GoRouteData {
+  @override
+  Widget build(BuildContext context, GoRouterState state) {
+    return const SettingPage();
+  }
+}
+
+@TypedGoRoute<GameRouter>(path: '/game')
+class GameRouter extends GoRouteData {
+  final String cardName;
+  final String assetPath;
+  final List<int> answer;
+
+  GameRouter({
+    required this.cardName,
+    required this.assetPath,
+    required this.answer,
+  });
+
+  @override
+  Widget build(BuildContext context, GoRouterState state) {
+    return GamePage(
+      card: CardItem(
+        cardName: cardName,
+        assetPath: assetPath,
+        answer: answer,
+      ),
+    );
+  }
+}
+
+@TypedGoRoute<AboutRouter>(path: '/about')
+class AboutRouter extends GoRouteData {
+  @override
+  Widget build(BuildContext context, GoRouterState state) {
+    return const AboutPage();
+  }
+}

+ 34 - 0
lib/utils/utils.dart

@@ -0,0 +1,34 @@
+
+import 'dart:math';
+
+import 'package:flutter/animation.dart';
+
+List<int> generateIntList() {
+  List<int> list = List.generate(6, (i) => i);
+
+  var random = Random.secure();
+  for (int i = 0; i < 3; i++) {
+    int i = random.nextInt(list.length);
+    int j = random.nextInt(list.length);
+
+    int temp = list[i];
+    list[i] = list[j];
+    list[j] = temp;
+  }
+
+  return list;
+}
+
+// List<Curve> curves = <Curve>[
+//   Curves.easeIn,
+//   Curves.easeInCirc,
+//   Curves.easeIn,
+//   Curves.easeIn,
+//   Curves.easeIn,
+//   Curves.easeIn,
+//   Curves.easeIn,
+// ];
+//
+// double curveProcess(double value){
+//
+// }

+ 0 - 3
packages/widget/lib/src/battle_layout.dart

@@ -59,9 +59,6 @@ class BattleBoard extends StatefulWidget {
 }
 
 class _BattleBoardState extends State<BattleBoard> {
-  void _addWithSlot(List<LayoutId> children, _BattleSlot slot, Widget child) {
-    children.add(LayoutId(id: slot, child: child));
-  }
 
   @override
   Widget build(BuildContext context) {

+ 2 - 2
packages/widget/lib/src/constant.dart

@@ -14,7 +14,7 @@ const int _kBoardWidth = _kTextureWidth;
 const int _kBoardHeight = 2253;
 const int _kCardWidth = 1280;
 const int _kCardHeight = 1826;
-const int _kCardPadding = 35;
+const int _kCardPadding = 24;
 
 const double kTextureAspectRatio = _kTextureWidth / _kTextureHeight;
 const double kBoardWidthAspectRatio = _kBoardWidth / _kTextureWidth;
@@ -31,7 +31,7 @@ const double kCardOverflowAspectRatio = _kCardOverflowHeight / _kTextureHeight;
 const double kCardCoverAspectRatio = _kCardPadding / _kBoardWidth;
 
 /// 推钮的直径大小
-const int _kButtonSize = 200;
+const int _kButtonSize = 175;
 const double kButtonAspectRatio = _kButtonSize / _kBoardWidth;
 
 /// 推钮滑轨线的宽度

+ 285 - 397
pubspec.lock

@@ -1,20 +1,28 @@
 # Generated by pub
 # See https://dart.dev/tools/pub/glossary#lockfile
 packages:
-  archive:
+  _fe_analyzer_shared:
     dependency: transitive
     description:
-      name: archive
-      sha256: "6bd38d335f0954f5fad9c79e614604fbf03a0e5b975923dd001b6ea965ef5b4b"
-      url: "https://pub.dev"
+      name: _fe_analyzer_shared
+      sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7"
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "3.6.0"
+    version: "67.0.0"
+  analyzer:
+    dependency: transitive
+    description:
+      name: analyzer
+      sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "6.4.1"
   args:
     dependency: transitive
     description:
       name: args
       sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "2.5.0"
   async:
@@ -22,111 +30,135 @@ packages:
     description:
       name: async
       sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "2.11.0"
-  audioplayers:
+  boolean_selector:
     dependency: transitive
     description:
-      name: audioplayers
-      sha256: "752039d6aa752597c98ec212e9759519061759e402e7da59a511f39d43aa07d2"
-      url: "https://pub.dev"
+      name: boolean_selector
+      sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "6.0.0"
-  audioplayers_android:
+    version: "2.1.1"
+  build:
     dependency: transitive
     description:
-      name: audioplayers_android
-      sha256: de576b890befe27175c2f511ba8b742bec83765fa97c3ce4282bba46212f58e4
-      url: "https://pub.dev"
+      name: build
+      sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "5.0.0"
-  audioplayers_darwin:
+    version: "2.4.1"
+  build_config:
     dependency: transitive
     description:
-      name: audioplayers_darwin
-      sha256: e507887f3ff18d8e5a10a668d7bedc28206b12e10b98347797257c6ae1019c3b
-      url: "https://pub.dev"
+      name: build_config
+      sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "6.0.0"
-  audioplayers_linux:
+    version: "1.1.1"
+  build_daemon:
     dependency: transitive
     description:
-      name: audioplayers_linux
-      sha256: "3d3d244c90436115417f170426ce768856d8fe4dfc5ed66a049d2890acfa82f9"
-      url: "https://pub.dev"
+      name: build_daemon
+      sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "4.0.0"
-  audioplayers_platform_interface:
+    version: "4.0.2"
+  build_resolvers:
     dependency: transitive
     description:
-      name: audioplayers_platform_interface
-      sha256: "6834dd48dfb7bc6c2404998ebdd161f79cd3774a7e6779e1348d54a3bfdcfaa5"
-      url: "https://pub.dev"
+      name: build_resolvers
+      sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "7.0.0"
-  audioplayers_web:
-    dependency: transitive
+    version: "2.4.2"
+  build_runner:
+    dependency: "direct dev"
     description:
-      name: audioplayers_web
-      sha256: db8fc420dadf80da18e2286c18e746fb4c3b2c5adbf0c963299dde046828886d
-      url: "https://pub.dev"
+      name: build_runner
+      sha256: "644dc98a0f179b872f612d3eb627924b578897c629788e858157fa5e704ca0c7"
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "5.0.0"
-  audioplayers_windows:
+    version: "2.4.11"
+  build_runner_core:
     dependency: transitive
     description:
-      name: audioplayers_windows
-      sha256: "8605762dddba992138d476f6a0c3afd9df30ac5b96039929063eceed416795c2"
-      url: "https://pub.dev"
+      name: build_runner_core
+      sha256: e3c79f69a64bdfcd8a776a3c28db4eb6e3fb5356d013ae5eb2e52007706d5dbe
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "4.0.0"
-  bloc:
+    version: "7.3.1"
+  built_collection:
     dependency: transitive
     description:
-      name: bloc
-      sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e"
-      url: "https://pub.dev"
+      name: built_collection
+      sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "8.1.4"
-  boolean_selector:
+    version: "5.1.1"
+  built_value:
     dependency: transitive
     description:
-      name: boolean_selector
-      sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
-      url: "https://pub.dev"
+      name: built_value
+      sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "2.1.1"
+    version: "8.9.2"
   characters:
     dependency: transitive
     description:
       name: characters
       sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.3.0"
+  checked_yaml:
+    dependency: transitive
+    description:
+      name: checked_yaml
+      sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.3"
   clock:
     dependency: transitive
     description:
       name: clock
       sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.1.1"
+  code_builder:
+    dependency: transitive
+    description:
+      name: code_builder
+      sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "4.10.0"
   collection:
     dependency: transitive
     description:
       name: collection
       sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.18.0"
+  convert:
+    dependency: transitive
+    description:
+      name: convert
+      sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.1.1"
   crypto:
     dependency: transitive
     description:
       name: crypto
       sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "3.0.3"
   cupertino_icons:
@@ -134,39 +166,31 @@ packages:
     description:
       name: cupertino_icons
       sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.0.8"
-  dev:
+  dart_style:
     dependency: transitive
     description:
-      name: dev
-      sha256: e7e806af20d53e293a7878212d2246d3e9fccd2b49d597600f9898ed83501cb4
-      url: "https://pub.dev"
+      name: dart_style
+      sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9"
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "1.0.0"
+    version: "2.3.6"
   fake_async:
     dependency: transitive
     description:
       name: fake_async
       sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.3.1"
-  ffi:
-    dependency: transitive
-    description:
-      name: ffi
-      sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
-      url: "https://pub.dev"
-    source: hosted
-    version: "2.1.2"
   file:
     dependency: transitive
     description:
       name: file
       sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "7.0.0"
   fixnum:
@@ -174,116 +198,20 @@ packages:
     description:
       name: fixnum
       sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.1.0"
-  flame:
-    dependency: "direct main"
-    description:
-      name: flame
-      sha256: "79133dc46a3ff870950f41d0dc1598414e7bd7ae2c29bd9f0a9de208d9a70cb7"
-      url: "https://pub.dev"
-    source: hosted
-    version: "1.18.0"
-  flame_audio:
-    dependency: "direct main"
-    description:
-      name: flame_audio
-      sha256: "32e5788945469cebb807e741027e645a737e2618afc9b682e7f48607e0637f48"
-      url: "https://pub.dev"
-    source: hosted
-    version: "2.10.2"
-  flame_bloc:
-    dependency: "direct main"
-    description:
-      name: flame_bloc
-      sha256: "19d907204b65f81b08adf71da02e632e68757b1a6738378d8dd4bc024c1660b8"
-      url: "https://pub.dev"
-    source: hosted
-    version: "1.12.0"
-  flame_forge2d:
-    dependency: "direct main"
-    description:
-      name: flame_forge2d
-      sha256: "1ec1c5b4978b64d2d16ca90f86de469959991ef996970866c3f9de580b3dbe40"
-      url: "https://pub.dev"
-    source: hosted
-    version: "0.18.1"
-  flame_isolate:
-    dependency: "direct main"
-    description:
-      name: flame_isolate
-      sha256: "2c7848226b355fd631bec114a19bcc5b9b8f1c3538798a0e9c0fae6ec8f48f8b"
-      url: "https://pub.dev"
-    source: hosted
-    version: "0.6.1"
-  flame_lottie:
-    dependency: "direct main"
-    description:
-      name: flame_lottie
-      sha256: e3a6a3326a53a6d1ebfc5483220cb0979cfccbb58e5e8d68c9f0847782659be6
-      url: "https://pub.dev"
-    source: hosted
-    version: "0.4.1"
-  flame_markdown:
-    dependency: "direct main"
-    description:
-      name: flame_markdown
-      sha256: "6a4bb403ed66161c59061d54c8910179b213673f16fe1215108f0d419cec9c83"
-      url: "https://pub.dev"
-    source: hosted
-    version: "0.2.1"
-  flame_network_assets:
-    dependency: "direct main"
-    description:
-      name: flame_network_assets
-      sha256: "8fa0981620ecc86a17a6efdafaea1d1e3ccde4e42bbe50558161c53c38f52f94"
-      url: "https://pub.dev"
-    source: hosted
-    version: "0.3.2"
-  flame_riverpod:
-    dependency: "direct main"
-    description:
-      name: flame_riverpod
-      sha256: e04d47cf43c9e2bfb4a70cc8f5dbcbe7e7b2b1e1f2b8ff8ad1ef7b90e2aec09d
-      url: "https://pub.dev"
-    source: hosted
-    version: "5.4.2"
-  flame_svg:
-    dependency: "direct main"
-    description:
-      name: flame_svg
-      sha256: b8da1bd3780cc1f45b72f451800c9d5392db5eb6fe1efb820cc47d5a8d3c4b1f
-      url: "https://pub.dev"
-    source: hosted
-    version: "1.10.2"
-  flame_tiled:
-    dependency: "direct main"
-    description:
-      name: flame_tiled
-      sha256: "519dc91412dc617203ed182712c2d44343ce2ab103ab81921cd4032b10b0cc2b"
-      url: "https://pub.dev"
-    source: hosted
-    version: "1.20.2"
   flutter:
     dependency: "direct main"
     description: flutter
     source: sdk
     version: "0.0.0"
-  flutter_bloc:
-    dependency: transitive
-    description:
-      name: flutter_bloc
-      sha256: f0ecf6e6eb955193ca60af2d5ca39565a86b8a142452c5b24d96fb477428f4d2
-      url: "https://pub.dev"
-    source: hosted
-    version: "8.1.5"
   flutter_lints:
     dependency: "direct dev"
     description:
       name: flutter_lints
       sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "3.0.2"
   flutter_riverpod:
@@ -291,17 +219,9 @@ packages:
     description:
       name: flutter_riverpod
       sha256: "0f1974eff5bbe774bf1d870e406fc6f29e3d6f1c46bd9c58e7172ff68a785d7d"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "2.5.1"
-  flutter_svg:
-    dependency: transitive
-    description:
-      name: flutter_svg
-      sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2"
-      url: "https://pub.dev"
-    source: hosted
-    version: "2.0.10+1"
   flutter_test:
     dependency: "direct dev"
     description: flutter
@@ -312,52 +232,92 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
-  forge2d:
+  frontend_server_client:
     dependency: transitive
     description:
-      name: forge2d
-      sha256: "40915333b688ddaaa616d9c8ab9ff205faea0adf83dddc1a6e617694ffa9e16e"
-      url: "https://pub.dev"
+      name: frontend_server_client
+      sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "0.13.0"
-  gestures:
+    version: "4.0.0"
+  glob:
     dependency: transitive
     description:
-      name: gestures
-      sha256: "6e75e4ba1ad033a8be9a682974dfe6a2be96ab07b4aa8335ed37bbecb75b7770"
-      url: "https://pub.dev"
+      name: glob
+      sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "1.0.0"
-  http:
+    version: "2.1.2"
+  go_router:
+    dependency: "direct main"
+    description:
+      name: go_router
+      sha256: cdae1b9c8bd7efadcef6112e81c903662ef2ce105cbd220a04bbb7c3425b5554
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "14.2.0"
+  go_router_builder:
+    dependency: "direct dev"
+    description:
+      name: go_router_builder
+      sha256: "51eca134e77d84c78a5297242ed45dc6988c66531a97cb4bf49d149e8f60d809"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.7.0"
+  graphs:
     dependency: transitive
     description:
-      name: http
-      sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
-      url: "https://pub.dev"
+      name: graphs
+      sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "1.2.1"
+    version: "2.3.1"
+  http_multi_server:
+    dependency: transitive
+    description:
+      name: http_multi_server
+      sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.2.1"
   http_parser:
     dependency: transitive
     description:
       name: http_parser
       sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "4.0.2"
-  integral_isolates:
+  io:
     dependency: transitive
     description:
-      name: integral_isolates
-      sha256: "62b1b45ea6350edc92d555aa1a98cbda09836b42e51e19e39d49bc39a686e601"
-      url: "https://pub.dev"
+      name: io
+      sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "0.5.1"
+    version: "1.0.4"
+  js:
+    dependency: transitive
+    description:
+      name: js
+      sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.7.1"
+  json_annotation:
+    dependency: transitive
+    description:
+      name: json_annotation
+      sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "4.9.0"
   leak_tracker:
     dependency: transitive
     description:
       name: leak_tracker
       sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "10.0.4"
   leak_tracker_flutter_testing:
@@ -365,7 +325,7 @@ packages:
     description:
       name: leak_tracker_flutter_testing
       sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "3.0.3"
   leak_tracker_testing:
@@ -373,7 +333,7 @@ packages:
     description:
       name: leak_tracker_testing
       sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "3.0.1"
   lints:
@@ -381,31 +341,23 @@ packages:
     description:
       name: lints
       sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "3.0.0"
-  lottie:
-    dependency: transitive
-    description:
-      name: lottie
-      sha256: "6a24ade5d3d918c306bb1c21a6b9a04aab0489d51a2582522eea820b4093b62b"
-      url: "https://pub.dev"
-    source: hosted
-    version: "3.1.2"
-  markdown:
+  logging:
     dependency: transitive
     description:
-      name: markdown
-      sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051
-      url: "https://pub.dev"
+      name: logging
+      sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "7.2.2"
+    version: "1.2.0"
   matcher:
     dependency: transitive
     description:
       name: matcher
       sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "0.12.16+1"
   material_color_utilities:
@@ -413,7 +365,7 @@ packages:
     description:
       name: material_color_utilities
       sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "0.8.0"
   meta:
@@ -421,121 +373,57 @@ packages:
     description:
       name: meta
       sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.12.0"
-  nested:
+  mime:
     dependency: transitive
     description:
-      name: nested
-      sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
-      url: "https://pub.dev"
+      name: mime
+      sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2"
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "1.0.0"
-  ordered_set:
+    version: "1.0.5"
+  package_config:
     dependency: transitive
     description:
-      name: ordered_set
-      sha256: "1bfaaaee0419e43ecc9eaebd410eb4bd5039657b72011de75ff3e2915c9aac60"
-      url: "https://pub.dev"
+      name: package_config
+      sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "5.0.3"
+    version: "2.1.0"
   path:
     dependency: transitive
     description:
       name: path
       sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.9.0"
-  path_parsing:
-    dependency: transitive
-    description:
-      name: path_parsing
-      sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
-      url: "https://pub.dev"
-    source: hosted
-    version: "1.0.1"
-  path_provider:
-    dependency: transitive
-    description:
-      name: path_provider
-      sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161
-      url: "https://pub.dev"
-    source: hosted
-    version: "2.1.3"
-  path_provider_android:
-    dependency: transitive
-    description:
-      name: path_provider_android
-      sha256: "9c96da072b421e98183f9ea7464898428e764bc0ce5567f27ec8693442e72514"
-      url: "https://pub.dev"
-    source: hosted
-    version: "2.2.5"
-  path_provider_foundation:
-    dependency: transitive
-    description:
-      name: path_provider_foundation
-      sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
-      url: "https://pub.dev"
-    source: hosted
-    version: "2.4.0"
-  path_provider_linux:
-    dependency: transitive
-    description:
-      name: path_provider_linux
-      sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
-      url: "https://pub.dev"
-    source: hosted
-    version: "2.2.1"
-  path_provider_platform_interface:
-    dependency: transitive
-    description:
-      name: path_provider_platform_interface
-      sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
-      url: "https://pub.dev"
-    source: hosted
-    version: "2.1.2"
-  path_provider_windows:
-    dependency: transitive
-    description:
-      name: path_provider_windows
-      sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
-      url: "https://pub.dev"
-    source: hosted
-    version: "2.2.1"
-  petitparser:
-    dependency: transitive
-    description:
-      name: petitparser
-      sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
-      url: "https://pub.dev"
-    source: hosted
-    version: "6.0.2"
-  platform:
+  pool:
     dependency: transitive
     description:
-      name: platform
-      sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
-      url: "https://pub.dev"
+      name: pool
+      sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "3.1.4"
-  plugin_platform_interface:
+    version: "1.5.1"
+  pub_semver:
     dependency: transitive
     description:
-      name: plugin_platform_interface
-      sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
-      url: "https://pub.dev"
+      name: pub_semver
+      sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "2.1.8"
-  provider:
+    version: "2.1.4"
+  pubspec_parse:
     dependency: transitive
     description:
-      name: provider
-      sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
-      url: "https://pub.dev"
+      name: pubspec_parse
+      sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "6.1.2"
+    version: "1.3.0"
   repository:
     dependency: "direct main"
     description:
@@ -548,36 +436,60 @@ packages:
     description:
       name: riverpod
       sha256: f21b32ffd26a36555e501b04f4a5dca43ed59e16343f1a30c13632b2351dfa4d
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "2.5.1"
+  shelf:
+    dependency: transitive
+    description:
+      name: shelf
+      sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.4.1"
+  shelf_web_socket:
+    dependency: transitive
+    description:
+      name: shelf_web_socket
+      sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.0"
   sky_engine:
     dependency: transitive
     description: flutter
     source: sdk
     version: "0.0.99"
+  source_gen:
+    dependency: transitive
+    description:
+      name: source_gen
+      sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.5.0"
+  source_helper:
+    dependency: transitive
+    description:
+      name: source_helper
+      sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.3.4"
   source_span:
     dependency: transitive
     description:
       name: source_span
       sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.10.0"
-  sprintf:
-    dependency: transitive
-    description:
-      name: sprintf
-      sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
-      url: "https://pub.dev"
-    source: hosted
-    version: "7.0.0"
   stack_trace:
     dependency: transitive
     description:
       name: stack_trace
       sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.11.1"
   state_notifier:
@@ -585,7 +497,7 @@ packages:
     description:
       name: state_notifier
       sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.0.0"
   stream_channel:
@@ -593,31 +505,31 @@ packages:
     description:
       name: stream_channel
       sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "2.1.2"
+  stream_transform:
+    dependency: transitive
+    description:
+      name: stream_transform
+      sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.0"
   string_scanner:
     dependency: transitive
     description:
       name: string_scanner
       sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.2.0"
-  synchronized:
-    dependency: transitive
-    description:
-      name: synchronized
-      sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558"
-      url: "https://pub.dev"
-    source: hosted
-    version: "3.1.0+1"
   term_glyph:
     dependency: transitive
     description:
       name: term_glyph
       sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.2.1"
   test_api:
@@ -625,63 +537,31 @@ packages:
     description:
       name: test_api
       sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "0.7.0"
-  tiled:
+  timing:
     dependency: transitive
     description:
-      name: tiled
-      sha256: "988a57a07df280bb4a5d722c9e400b282d8d9a652b5a2afc8b68e1308bbf8222"
-      url: "https://pub.dev"
+      name: timing
+      sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "0.10.2"
+    version: "1.0.1"
   typed_data:
     dependency: transitive
     description:
       name: typed_data
       sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.3.2"
-  uuid:
-    dependency: transitive
-    description:
-      name: uuid
-      sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8"
-      url: "https://pub.dev"
-    source: hosted
-    version: "4.4.0"
-  vector_graphics:
-    dependency: transitive
-    description:
-      name: vector_graphics
-      sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3"
-      url: "https://pub.dev"
-    source: hosted
-    version: "1.1.11+1"
-  vector_graphics_codec:
-    dependency: transitive
-    description:
-      name: vector_graphics_codec
-      sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da
-      url: "https://pub.dev"
-    source: hosted
-    version: "1.1.11+1"
-  vector_graphics_compiler:
-    dependency: transitive
-    description:
-      name: vector_graphics_compiler
-      sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81"
-      url: "https://pub.dev"
-    source: hosted
-    version: "1.1.11+1"
   vector_math:
     dependency: transitive
     description:
       name: vector_math
       sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "2.1.4"
   vm_service:
@@ -689,17 +569,41 @@ packages:
     description:
       name: vm_service
       sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "14.2.1"
+  watcher:
+    dependency: transitive
+    description:
+      name: watcher
+      sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.1.0"
   web:
     dependency: transitive
     description:
       name: web
       sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
-      url: "https://pub.dev"
+      url: "https://pub.flutter-io.cn"
     source: hosted
     version: "0.5.1"
+  web_socket:
+    dependency: transitive
+    description:
+      name: web_socket
+      sha256: "24301d8c293ce6fe327ffe6f59d8fd8834735f0ec36e4fd383ec7ff8a64aa078"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.1.5"
+  web_socket_channel:
+    dependency: transitive
+    description:
+      name: web_socket_channel
+      sha256: a2d56211ee4d35d9b344d9d4ce60f362e4f5d1aafb988302906bd732bc731276
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.0.0"
   widget:
     dependency: "direct main"
     description:
@@ -707,30 +611,14 @@ packages:
       relative: true
     source: path
     version: "0.0.1"
-  win32:
-    dependency: transitive
-    description:
-      name: win32
-      sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
-      url: "https://pub.dev"
-    source: hosted
-    version: "5.5.1"
-  xdg_directories:
+  yaml:
     dependency: transitive
     description:
-      name: xdg_directories
-      sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
-      url: "https://pub.dev"
+      name: yaml
+      sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
+      url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "1.0.4"
-  xml:
-    dependency: transitive
-    description:
-      name: xml
-      sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
-      url: "https://pub.dev"
-    source: hosted
-    version: "6.5.0"
+    version: "3.1.2"
 sdks:
   dart: ">=3.4.0 <4.0.0"
   flutter: ">=3.22.0"

+ 14 - 0
pubspec.yaml

@@ -12,6 +12,7 @@ dependencies:
     sdk: flutter
 
   cupertino_icons: ^1.0.6
+  go_router: ^14.2.0
 
   riverpod: ^2.5.1
   flutter_riverpod: ^2.5.1
@@ -26,9 +27,22 @@ dev_dependencies:
     sdk: flutter
 
   flutter_lints: ^3.0.0
+  build_runner: ^2.0.0
+  go_router_builder: ^2.7.0
 
 flutter:
   uses-material-design: true
 
   assets:
     - assets/images/background.png
+    - assets/images/test.jpg
+    # 卡片素材包
+    - assets/cards/chs2-6.jpg
+    - assets/cards/chs2-14.jpg
+    - assets/cards/chs2-16.jpg
+    - assets/cards/cms2-1.jpg
+    - assets/cards/cms2-5.jpg
+    - assets/cards/cms2-15.jpg
+    - assets/cards/css2-2.jpg
+    - assets/cards/css2-11.jpg
+    - assets/cards/css2-13.jpg