import 'dart:math'; import 'package:flutter_web/material.dart'; import 'package:vision_challenge/packages/flutter_redux.dart'; import 'package:vision_challenge/packages/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 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> 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( // 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: [ 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 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> 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> newBoard(score) { var size = score < 7 ? score + 3 : 10, rng = Random(), bingoRow = rng.nextInt(size), bingoCol = rng.nextInt(size); List> board = []; for (var i = 0; i < size; i++) { List row = []; for (var j = 0; j < size; j++) row.add(i == bingoRow && j == bingoCol ? 1 : 0); board.add(row); } return board; }