mirror of https://github.com/flutter/samples.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
208 lines
7.2 KiB
208 lines
7.2 KiB
import 'dart:math';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_redux/flutter_redux.dart';
|
|
import 'package:redux/redux.dart';
|
|
|
|
setText(text, size, color) => Text(text,
|
|
style: TextStyle(
|
|
fontSize: size,
|
|
color: color,
|
|
fontWeight: FontWeight.bold,
|
|
decoration: TextDecoration.none));
|
|
|
|
pad(double left, double top) => EdgeInsets.fromLTRB(left, top, 0, 0);
|
|
|
|
setBg(name) => BoxDecoration(
|
|
image: DecorationImage(
|
|
fit: BoxFit.cover,
|
|
alignment: Alignment.topLeft,
|
|
image: AssetImage(name)));
|
|
|
|
class Game extends StatelessWidget {
|
|
final Store<AppState> store;
|
|
Game(this.store);
|
|
_grade(int score) => [10, 20, 30, 35, 40, 45, 99]
|
|
.where((i) => i > score)
|
|
.reduce(min)
|
|
.toString();
|
|
|
|
_createBoard(double size, List<List<int>> blocks, int depth,
|
|
MaterialColor color) =>
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
children: blocks
|
|
.map((cols) => Column(
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
children: cols
|
|
.map((item) => Flexible(
|
|
child: GestureDetector(
|
|
onTap: () {
|
|
if (item == 1) store.dispatch(Action.next);
|
|
},
|
|
child: Container(
|
|
width: size,
|
|
height: size,
|
|
color: item > 0 ? color[depth] : color)),
|
|
))
|
|
.toList()))
|
|
.toList());
|
|
|
|
@override
|
|
Widget build(BuildContext context) => StoreConnector<AppState, AppState>(
|
|
// onInit: (state) => ShakeDetector.autoStart(
|
|
// onPhoneShake: () => store.dispatch(Action.shake)),
|
|
converter: (store) => store.state,
|
|
builder: (context, state) {
|
|
var w = MediaQuery.of(context).size.height / 16 * 9,
|
|
size = w / (state.board.length + 1),
|
|
depth = [1 + state.score ~/ 5, 4].reduce(min) * 100,
|
|
colors = [
|
|
Colors.blue,
|
|
Colors.orange,
|
|
Colors.pink,
|
|
Colors.purple,
|
|
Colors.cyan
|
|
];
|
|
|
|
return Scaffold(
|
|
backgroundColor: Color(0xFFBCE1F6),
|
|
body: Center(
|
|
child: SizedBox(
|
|
height: MediaQuery.of(context).size.height,
|
|
width: MediaQuery.of(context).size.height / 16 * 9,
|
|
child: Container(
|
|
decoration: setBg(state.page < 0 ? 'p0.jpg' : 'p1.jpg'),
|
|
child: state.page >= 0
|
|
? Column(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: <Widget>[
|
|
Container(
|
|
height: w * 0.325,
|
|
padding: pad(0, w * 0.145),
|
|
child: setText(state.score.toString(),
|
|
w * 0.2, Colors.white)),
|
|
Container(
|
|
height: w * 0.35,
|
|
padding: pad(w * 0.69, state.page * 7.0),
|
|
child: state.page < 1
|
|
? Timer(
|
|
onEnd: () =>
|
|
store.dispatch(Action.end),
|
|
width: w)
|
|
: setText('End', w * 0.08, Colors.red)),
|
|
state.page < 1
|
|
? Container(
|
|
width: w,
|
|
height: w * 1.05,
|
|
padding: pad(0, w * 0.05),
|
|
child: _createBoard(
|
|
size,
|
|
state.board,
|
|
depth,
|
|
colors[
|
|
state.count % colors.length]))
|
|
: Container(
|
|
width: w,
|
|
height: w,
|
|
decoration:
|
|
setBg(_grade(state.score) + '.png'))
|
|
])
|
|
: Container()),
|
|
),
|
|
),
|
|
floatingActionButton: state.page != 0
|
|
? Container(
|
|
// width: w * 0.2,
|
|
// height: w * 0.2,
|
|
child: FloatingActionButton(
|
|
child: Icon(
|
|
state.page < 1 ? Icons.play_arrow : Icons.refresh),
|
|
onPressed: () => store.dispatch(Action.start)))
|
|
: Container());
|
|
});
|
|
}
|
|
|
|
class Timer extends StatefulWidget {
|
|
Timer({this.onEnd, this.width});
|
|
final VoidCallback onEnd;
|
|
final double width;
|
|
@override
|
|
_TimerState createState() => _TimerState();
|
|
}
|
|
|
|
class _TimerState extends State<Timer> with TickerProviderStateMixin {
|
|
Animation _animate;
|
|
int _sec = 31;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_animate = StepTween(begin: _sec, end: 0).animate(
|
|
AnimationController(duration: Duration(seconds: _sec), vsync: this)
|
|
..forward(from: 0.0))
|
|
..addStatusListener((AnimationStatus s) {
|
|
if (s == AnimationStatus.completed) widget.onEnd();
|
|
});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) => AnimatedBuilder(
|
|
animation: _animate,
|
|
builder: (BuildContext context, Widget child) => setText(
|
|
_animate.value.toString().padLeft(2, '0'),
|
|
widget.width * 0.12,
|
|
Colors.green));
|
|
}
|
|
|
|
//REDUX
|
|
@immutable
|
|
class AppState {
|
|
final int score, page, count;
|
|
final List<List<int>> board;
|
|
AppState({this.score, this.page, this.board, this.count});
|
|
AppState.init()
|
|
: score = 0,
|
|
page = -1,
|
|
count = 0,
|
|
board = newBoard(0);
|
|
}
|
|
|
|
enum Action { next, end, start, shake }
|
|
|
|
AppState reducer(AppState s, act) {
|
|
switch (act) {
|
|
case Action.next:
|
|
return AppState(
|
|
score: s.score + 1,
|
|
page: s.page,
|
|
count: s.count,
|
|
board: newBoard(s.score + 1));
|
|
case Action.end:
|
|
return AppState(
|
|
score: s.score, page: 1, count: s.count + 1, board: s.board);
|
|
case Action.start:
|
|
return AppState(score: 0, page: 0, count: s.count, board: newBoard(0));
|
|
case Action.shake:
|
|
return AppState(
|
|
score: s.score, page: s.page, count: s.count + 1, board: s.board);
|
|
default:
|
|
return s;
|
|
}
|
|
}
|
|
|
|
List<List<int>> newBoard(score) {
|
|
var size = score < 7 ? score + 3 : 10,
|
|
rng = Random(),
|
|
bingoRow = rng.nextInt(size),
|
|
bingoCol = rng.nextInt(size);
|
|
List<List<int>> board = [];
|
|
for (var i = 0; i < size; i++) {
|
|
List<int> row = [];
|
|
for (var j = 0; j < size; j++)
|
|
row.add(i == bingoRow && j == bingoCol ? 1 : 0);
|
|
board.add(row);
|
|
}
|
|
return board;
|
|
}
|