File lib/main.dart changed (mode: 100644) (index d9d9093..2b290d1) |
1 |
1 |
import 'package:flutter/material.dart'; |
import 'package:flutter/material.dart'; |
|
2 |
|
import 'package:flutter/services.dart'; |
2 |
3 |
import 'routes/battle-page.dart'; |
import 'routes/battle-page.dart'; |
|
4 |
|
import './routes/main-menu.dart'; |
|
5 |
|
import 'dart:io'; |
3 |
6 |
|
|
4 |
7 |
void main() { |
void main() { |
5 |
8 |
// runApp(MyApp()); |
// runApp(MyApp()); |
6 |
9 |
runApp(ChessApp()); |
runApp(ChessApp()); |
|
10 |
|
|
|
11 |
|
/* 设置公支持竖屏 */ |
|
12 |
|
SystemChrome.setPreferredOrientations( |
|
13 |
|
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown], |
|
14 |
|
); |
|
15 |
|
|
|
16 |
|
/* 不显示状态栏(全屏显示) */ |
|
17 |
|
if (Platform.isAndroid) { |
|
18 |
|
//判断是否为Android系统 |
|
19 |
|
SystemChrome.setSystemUIOverlayStyle( |
|
20 |
|
SystemUiOverlayStyle(statusBarColor: Colors.transparent), |
|
21 |
|
); |
|
22 |
|
} |
|
23 |
|
|
|
24 |
|
SystemChrome.setEnabledSystemUIOverlays([]); |
7 |
25 |
} |
} |
8 |
26 |
|
|
9 |
27 |
class ChessApp extends StatelessWidget { |
class ChessApp extends StatelessWidget { |
|
28 |
|
static const StatusBarHeight = 28.0; |
|
29 |
|
|
10 |
30 |
@override |
@override |
11 |
31 |
Widget build(BuildContext context) { |
Widget build(BuildContext context) { |
|
32 |
|
// return MaterialApp( |
|
33 |
|
// title: '中国象棋', |
|
34 |
|
// theme: ThemeData( |
|
35 |
|
// primarySwatch: Colors.lime, |
|
36 |
|
// visualDensity: VisualDensity.adaptivePlatformDensity, |
|
37 |
|
// ), |
|
38 |
|
// debugShowCheckedModeBanner: false, //禁止显示 App 右上角的一个「Debug」字样的条幅 |
|
39 |
|
// home: BattlePage(), |
|
40 |
|
// ); |
12 |
41 |
return MaterialApp( |
return MaterialApp( |
13 |
|
title: '中国象棋', |
|
14 |
42 |
theme: ThemeData( |
theme: ThemeData( |
15 |
|
primarySwatch: Colors.lime, |
|
16 |
|
visualDensity: VisualDensity.adaptivePlatformDensity, |
|
|
43 |
|
// primarySwatch: Colors.brown, //主题为棕色 |
|
44 |
|
primarySwatch: Colors.red, |
|
45 |
|
fontFamily: 'ChessTTF', |
17 |
46 |
), |
), |
18 |
|
debugShowCheckedModeBanner: false, //禁止显示 App 右上角的一个「Debug」字样的条幅 |
|
19 |
|
home: BattlePage(), |
|
|
47 |
|
home: MainMenu(), |
|
48 |
|
debugShowCheckedModeBanner: false, //不显示"Debug" |
20 |
49 |
); |
); |
21 |
50 |
} |
} |
22 |
51 |
} |
} |
File lib/routes/battle-page.dart changed (mode: 100644) (index 98a595b..eb7cac2) |
1 |
1 |
import 'package:chinese_chess/cchess/cc-base.dart'; |
import 'package:chinese_chess/cchess/cc-base.dart'; |
|
2 |
|
import 'package:chinese_chess/common/color-consts.dart'; |
2 |
3 |
import 'package:flutter/material.dart'; |
import 'package:flutter/material.dart'; |
3 |
4 |
import '../board/board-widget.dart'; |
import '../board/board-widget.dart'; |
4 |
5 |
import '../game/battle.dart'; |
import '../game/battle.dart'; |
|
6 |
|
import '../main.dart'; |
5 |
7 |
|
|
6 |
8 |
class BattlePage extends StatefulWidget { |
class BattlePage extends StatefulWidget { |
7 |
|
static const BoardMarginV = 10.0, BoardMarginH = 10.0; |
|
|
9 |
|
static double boardMargin = 10.0, screenPaddingH = 10.0; |
8 |
10 |
@override |
@override |
9 |
11 |
_BattlePageState createState() => _BattlePageState(); |
_BattlePageState createState() => _BattlePageState(); |
10 |
12 |
} |
} |
|
... |
... |
class _BattlePageState extends State<BattlePage> { |
16 |
18 |
Battle.shared.init(); //使用默认“新局”初始化棋子分布 |
Battle.shared.init(); //使用默认“新局”初始化棋子分布 |
17 |
19 |
} |
} |
18 |
20 |
|
|
|
21 |
|
void calcScreenPaddingH() { |
|
22 |
|
/* 当屏幕的纵横比小于16/9时,限制棋盘的宽度 */ |
|
23 |
|
final windowSize = MediaQuery.of(context).size; |
|
24 |
|
double height = windowSize.height, width = windowSize.width; |
|
25 |
|
|
|
26 |
|
if (height / width < 16.0 / 9.0) { |
|
27 |
|
width = height * 9 / 16; |
|
28 |
|
/* 横盘宽度之外的空间,分左右两边,由 screenPaddingH 来持有,布局时添加到 BoardWidget 外围水平边距 */ |
|
29 |
|
BattlePage.screenPaddingH = |
|
30 |
|
(windowSize.width - width) / 2 - BattlePage.boardMargin; |
|
31 |
|
} |
|
32 |
|
} |
|
33 |
|
|
19 |
34 |
/* 由 BattlePage 的 State 类来处理棋盘的点击事件 */ |
/* 由 BattlePage 的 State 类来处理棋盘的点击事件 */ |
20 |
35 |
onBoardTap(BuildContext context, int pos) { |
onBoardTap(BuildContext context, int pos) { |
21 |
36 |
// print('棋盘的index: $pos'); |
// print('棋盘的index: $pos'); |
|
... |
... |
class _BattlePageState extends State<BattlePage> { |
48 |
63 |
setState(() {}); //更新状态,重新绘制棋子 |
setState(() {}); //更新状态,重新绘制棋子 |
49 |
64 |
} |
} |
50 |
65 |
|
|
51 |
|
@override |
|
52 |
|
Widget build(BuildContext context) { |
|
|
66 |
|
/* 标题、活动状态、顶部按钮等 */ |
|
67 |
|
Widget createPageHeader() { |
|
68 |
|
final titleStyle = |
|
69 |
|
TextStyle(fontSize: 28, color: ColorConsts.DarkTextPrimary); |
|
70 |
|
final subTitleStyle = |
|
71 |
|
TextStyle(fontSize: 16, color: ColorConsts.DarkTextSecondary); |
|
72 |
|
|
|
73 |
|
return Container( |
|
74 |
|
margin: EdgeInsets.only(top: ChessApp.StatusBarHeight), |
|
75 |
|
child: Column( |
|
76 |
|
children: [ |
|
77 |
|
Row( |
|
78 |
|
children: [ |
|
79 |
|
IconButton( |
|
80 |
|
icon: |
|
81 |
|
Icon(Icons.arrow_back, color: ColorConsts.DarkTextPrimary), |
|
82 |
|
onPressed: () => Navigator.of(context).pop(), |
|
83 |
|
), |
|
84 |
|
Expanded(child: SizedBox()), |
|
85 |
|
Text('单机对战', style: titleStyle), |
|
86 |
|
Expanded(child: SizedBox()), |
|
87 |
|
IconButton( |
|
88 |
|
icon: Icon(Icons.settings, color: ColorConsts.DarkTextPrimary), |
|
89 |
|
onPressed: () {}, |
|
90 |
|
) |
|
91 |
|
], |
|
92 |
|
), |
|
93 |
|
Container( |
|
94 |
|
height: 4.0, |
|
95 |
|
width: 180.0, |
|
96 |
|
margin: EdgeInsets.only(bottom: 10), |
|
97 |
|
decoration: BoxDecoration( |
|
98 |
|
color: ColorConsts.BoardBackground, |
|
99 |
|
borderRadius: BorderRadius.circular(2), |
|
100 |
|
), |
|
101 |
|
), |
|
102 |
|
Container( |
|
103 |
|
padding: EdgeInsets.symmetric(horizontal: 16), |
|
104 |
|
child: Text('[游戏状态]', maxLines: 1, style: subTitleStyle), |
|
105 |
|
), |
|
106 |
|
], |
|
107 |
|
), |
|
108 |
|
); |
|
109 |
|
} |
|
110 |
|
|
|
111 |
|
Widget createBoard() { |
53 |
112 |
final windowSize = MediaQuery.of(context).size; |
final windowSize = MediaQuery.of(context).size; |
54 |
|
final boardHeight = windowSize.width - BattlePage.BoardMarginH * 2; |
|
55 |
113 |
|
|
56 |
|
return Scaffold( |
|
57 |
|
appBar: AppBar( |
|
58 |
|
title: Text('棋盘'), |
|
|
114 |
|
return Container( |
|
115 |
|
margin: EdgeInsets.symmetric( |
|
116 |
|
horizontal: BattlePage.screenPaddingH, |
|
117 |
|
vertical: BattlePage.boardMargin, |
|
118 |
|
), |
|
119 |
|
decoration: BoxDecoration( |
|
120 |
|
borderRadius: BorderRadius.circular(5), |
|
121 |
|
color: ColorConsts.BoardBackground, |
|
122 |
|
), |
|
123 |
|
child: BoardWidget( |
|
124 |
|
/* 这里将 screenPaddingH 作为边距,放置在 BoardWidget 左右,这样棋盘将水平居中显示 */ |
|
125 |
|
width: windowSize.width - BattlePage.screenPaddingH * 2, |
|
126 |
|
onBoardTap: onBoardTap, |
59 |
127 |
), |
), |
60 |
|
body: Container( |
|
61 |
|
margin: const EdgeInsets.symmetric( |
|
62 |
|
horizontal: BattlePage.BoardMarginH, |
|
63 |
|
vertical: BattlePage.BoardMarginV, |
|
|
128 |
|
); |
|
129 |
|
} |
|
130 |
|
|
|
131 |
|
/* 操作菜单栏 */ |
|
132 |
|
Widget createOperatorBar() { |
|
133 |
|
final buttonStyle = TextStyle(color: ColorConsts.Primary, fontSize: 20); |
|
134 |
|
return Container( |
|
135 |
|
decoration: BoxDecoration( |
|
136 |
|
borderRadius: BorderRadius.circular(5), |
|
137 |
|
color: ColorConsts.BoardBackground, |
|
138 |
|
), |
|
139 |
|
margin: EdgeInsets.symmetric(horizontal: BattlePage.screenPaddingH), |
|
140 |
|
padding: EdgeInsets.symmetric(vertical: 2), |
|
141 |
|
child: Row( |
|
142 |
|
children: [ |
|
143 |
|
Expanded(child: SizedBox()), |
|
144 |
|
FlatButton(onPressed: () {}, child: Text('新对局', style: buttonStyle)), |
|
145 |
|
Expanded(child: SizedBox()), |
|
146 |
|
FlatButton(onPressed: () {}, child: Text('悔棋', style: buttonStyle)), |
|
147 |
|
Expanded(child: SizedBox()), |
|
148 |
|
FlatButton(onPressed: () {}, child: Text('分析局面', style: buttonStyle)), |
|
149 |
|
Expanded(child: SizedBox()), |
|
150 |
|
], |
|
151 |
|
), |
|
152 |
|
); |
|
153 |
|
} |
|
154 |
|
|
|
155 |
|
/* 对于底部的空间的弹性处理 */ |
|
156 |
|
Widget buildFooter() { |
|
157 |
|
final size = MediaQuery.of(context).size; |
|
158 |
|
final manualText = '<暂无棋谱>'; |
|
159 |
|
|
|
160 |
|
if (size.height / size.width > 16 * 9) { |
|
161 |
|
/* 长屏幕,显示着法列表 */ |
|
162 |
|
return buildManualPanel(manualText); |
|
163 |
|
} else { |
|
164 |
|
/* 短屏幕显示一个按钮,点击它后弹出着法列表 */ |
|
165 |
|
return buildExpandableManaulPanel(manualText); |
|
166 |
|
} |
|
167 |
|
} |
|
168 |
|
|
|
169 |
|
/* 短屏幕显示一个按钮,点击它后弹出着法列表 */ |
|
170 |
|
Widget buildExpandableManaulPanel(String text) { |
|
171 |
|
final manualStyle = TextStyle(fontSize: 18, height: 1.5); |
|
172 |
|
|
|
173 |
|
return Expanded( |
|
174 |
|
child: IconButton( |
|
175 |
|
icon: Icon(Icons.expand_less, color: ColorConsts.DarkTextPrimary), |
|
176 |
|
onPressed: () { |
|
177 |
|
showDialog( |
|
178 |
|
context: context, |
|
179 |
|
barrierDismissible: false, |
|
180 |
|
builder: (BuildContext context) { |
|
181 |
|
return AlertDialog( |
|
182 |
|
title: Text('棋谱', style: TextStyle(color: ColorConsts.Primary)), |
|
183 |
|
content: SingleChildScrollView( |
|
184 |
|
child: Text(text, style: manualStyle)), |
|
185 |
|
actions: [ |
|
186 |
|
FlatButton( |
|
187 |
|
child: Text('好的'), |
|
188 |
|
onPressed: () => Navigator.of(context).pop(), |
|
189 |
|
), |
|
190 |
|
], |
|
191 |
|
); |
|
192 |
|
}, |
|
193 |
|
); |
|
194 |
|
}, |
|
195 |
|
), |
|
196 |
|
); |
|
197 |
|
} |
|
198 |
|
|
|
199 |
|
/* 长屏幕显示着法列表 */ |
|
200 |
|
Widget buildManualPanel(String text) { |
|
201 |
|
final manualStyle = TextStyle( |
|
202 |
|
fontSize: 18, |
|
203 |
|
color: ColorConsts.DarkTextSecondary, |
|
204 |
|
height: 1.5, |
|
205 |
|
); |
|
206 |
|
|
|
207 |
|
return Expanded( |
|
208 |
|
child: Container( |
|
209 |
|
margin: EdgeInsets.symmetric(vertical: 16), |
|
210 |
|
child: SingleChildScrollView( |
|
211 |
|
child: Text(text, style: manualStyle), |
64 |
212 |
), |
), |
65 |
|
child: BoardWidget(width: boardHeight, onBoardTap: onBoardTap), |
|
|
213 |
|
), |
|
214 |
|
); |
|
215 |
|
} |
|
216 |
|
|
|
217 |
|
// @override |
|
218 |
|
// Widget build(BuildContext context) { |
|
219 |
|
// final windowSize = MediaQuery.of(context).size; |
|
220 |
|
// final boardHeight = windowSize.width - BattlePage.BoardMarginH * 2; |
|
221 |
|
|
|
222 |
|
// return Scaffold( |
|
223 |
|
// appBar: AppBar( |
|
224 |
|
// title: Text('棋盘'), |
|
225 |
|
// ), |
|
226 |
|
// body: Container( |
|
227 |
|
// margin: const EdgeInsets.symmetric( |
|
228 |
|
// horizontal: BattlePage.BoardMarginH, |
|
229 |
|
// vertical: BattlePage.BoardMarginV, |
|
230 |
|
// ), |
|
231 |
|
// child: BoardWidget(width: boardHeight, onBoardTap: onBoardTap), |
|
232 |
|
// ), |
|
233 |
|
// ); |
|
234 |
|
// } |
|
235 |
|
|
|
236 |
|
@override |
|
237 |
|
Widget build(BuildContext context) { |
|
238 |
|
calcScreenPaddingH(); //先计算一次,确定 |
|
239 |
|
|
|
240 |
|
final header = createPageHeader(); |
|
241 |
|
final board = createBoard(); |
|
242 |
|
final operatorBar = createOperatorBar(); |
|
243 |
|
final footer = buildFooter(); |
|
244 |
|
return Scaffold( |
|
245 |
|
backgroundColor: ColorConsts.DarkBackground, |
|
246 |
|
body: Column( |
|
247 |
|
children: [ |
|
248 |
|
header, |
|
249 |
|
board, |
|
250 |
|
operatorBar, |
|
251 |
|
footer, |
|
252 |
|
], |
66 |
253 |
), |
), |
67 |
254 |
); |
); |
68 |
255 |
} |
} |
File lib/routes/main-menu.dart added (mode: 100644) (index 0000000..3912510) |
|
1 |
|
import 'package:flutter/material.dart'; |
|
2 |
|
import '../common/color-consts.dart'; |
|
3 |
|
import '../main.dart'; |
|
4 |
|
import 'battle-page.dart'; |
|
5 |
|
|
|
6 |
|
/* 游戏主菜单页 */ |
|
7 |
|
class MainMenu extends StatelessWidget { |
|
8 |
|
@override |
|
9 |
|
Widget build(BuildContext context) { |
|
10 |
|
final nameStyle = TextStyle( |
|
11 |
|
fontSize: 64, |
|
12 |
|
color: Colors.black, |
|
13 |
|
); |
|
14 |
|
|
|
15 |
|
final menuItemStyle = TextStyle( |
|
16 |
|
fontSize: 28, |
|
17 |
|
color: ColorConsts.Primary, |
|
18 |
|
); |
|
19 |
|
|
|
20 |
|
/* 标题及菜单项的布局 */ |
|
21 |
|
final menuItems = Center( |
|
22 |
|
child: Column( |
|
23 |
|
children: [ |
|
24 |
|
Expanded(child: SizedBox(), flex: 4), |
|
25 |
|
Text( |
|
26 |
|
'中国象棋', |
|
27 |
|
style: nameStyle, |
|
28 |
|
textAlign: TextAlign.center, |
|
29 |
|
), |
|
30 |
|
Expanded(child: SizedBox()), |
|
31 |
|
FlatButton( |
|
32 |
|
onPressed: () {}, |
|
33 |
|
child: Text('单机对战', style: menuItemStyle), |
|
34 |
|
), |
|
35 |
|
Expanded(child: SizedBox()), |
|
36 |
|
FlatButton( |
|
37 |
|
onPressed: () { |
|
38 |
|
Navigator.of(context).push( |
|
39 |
|
MaterialPageRoute(builder: (context) => BattlePage()), |
|
40 |
|
); |
|
41 |
|
}, |
|
42 |
|
child: Text('挑战云主机', style: menuItemStyle), |
|
43 |
|
), |
|
44 |
|
Expanded(child: SizedBox()), |
|
45 |
|
FlatButton( |
|
46 |
|
onPressed: () {}, |
|
47 |
|
child: Text('排行榜', style: menuItemStyle), |
|
48 |
|
), |
|
49 |
|
Expanded(child: SizedBox(), flex: 3), |
|
50 |
|
Text( |
|
51 |
|
'欲速不达,冰冻三尺', |
|
52 |
|
style: TextStyle(color: Colors.black54, fontSize: 16), |
|
53 |
|
), |
|
54 |
|
Expanded(child: SizedBox()), |
|
55 |
|
], |
|
56 |
|
), |
|
57 |
|
); |
|
58 |
|
|
|
59 |
|
return Scaffold( |
|
60 |
|
backgroundColor: ColorConsts.LightBackground, |
|
61 |
|
body: Stack( |
|
62 |
|
children: [ |
|
63 |
|
menuItems, |
|
64 |
|
/* 设置按纽 */ |
|
65 |
|
Positioned( |
|
66 |
|
top: ChessApp.StatusBarHeight, |
|
67 |
|
left: 10, |
|
68 |
|
child: IconButton( |
|
69 |
|
icon: Icon(Icons.settings, color: ColorConsts.Primary), |
|
70 |
|
onPressed: () {}, |
|
71 |
|
), |
|
72 |
|
), |
|
73 |
|
], |
|
74 |
|
), |
|
75 |
|
); |
|
76 |
|
} |
|
77 |
|
} |