Skip to content

Instantly share code, notes, and snippets.

@pedromassango
Created April 22, 2020 17:20
Show Gist options
  • Save pedromassango/478e5d48b3ac2ba34538f092febc7370 to your computer and use it in GitHub Desktop.
Save pedromassango/478e5d48b3ac2ba34538f092febc7370 to your computer and use it in GitHub Desktop.
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: TweenAnimationBuilder<double>(
duration: const Duration(milliseconds: 2000),
tween: Tween(begin: 0.0, end: 1.0),
curve: Interval(0.4, 1.0, curve: Curves.elasticOut),
child: _GamePad(),
builder: (_, value, child) {
return Transform.scale(
scale: value,
child: child,
);
},
),
);
}
}
class _Circle extends StatefulWidget {
final String value;
final bool showValue;
final bool isMatch;
final int index;
const _Circle({Key key,
@required this.index,
@required this.value,
@required this.showValue,
@required this.isMatch
}) : assert(value != null),
assert(showValue != null),
assert(isMatch != null),
super(key: key);
@override
__CircleState createState() => __CircleState();
}
class __CircleState extends State<_Circle> {
bool _showPreview = true;
void _schedulePreviewRemoval() async {
await Future.delayed(Duration(seconds: 4));
await Future.delayed(Duration(milliseconds: 370 * widget.index));
setState(() => _showPreview = false);
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
_schedulePreviewRemoval();
});
}
@override
Widget build(BuildContext context) {
final _baseColor = Colors.deepPurple;
final _matchColor = widget.isMatch ? Colors.green : _baseColor;
final _color = widget.showValue && widget.isMatch ? _matchColor :
widget.showValue ? Colors.amber : _baseColor;
return AnimatedContainer(
width: 32,
height: 32,
curve: Curves.fastLinearToSlowEaseIn,
duration: const Duration(milliseconds: 1800),
margin: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: _color,
borderRadius: BorderRadius.circular(8)
),
child: AnimatedOpacity(
opacity: _showPreview || widget.showValue ? 1.0 : 0.0,
duration: const Duration(milliseconds: 270),
child: Center(
child: Text(widget.value,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold
),),
),
),
);
}
}
class _GamePad extends StatefulWidget {
@override
__GamePadState createState() => __GamePadState();
}
class __GamePadState extends State<_GamePad> {
static const _size = 8;
List<List<Position>> _matrix;
Position _prevSelected;
final _random = Random();
int _getRandomValue(int index) {
return _random.nextInt(4);
}
void _seedMatrix() {
_matrix = List<List<Position>>(_size);
for (int i = 0; i < _size; i ++) {
final row = List<Position>(_size);
for (int j = 0; j < _size; j++) {
row[j] = Position(i, j, data: _getRandomValue(j));
}
_matrix[i] = row;
}
}
void _onTap(Position current) {
if (_prevSelected == null) {
final n = current.copy(showValue: true);
setState(() {
_prevSelected = n;
_matrix[current.x][current.y] = n;
});
} else if (_prevSelected.x == current.x &&
_prevSelected.y == current.y) {
final n = current.copy(showValue: !current.showValue);
setState(() {
_matrix[current.x][current.y] = n;
if (!n.showValue) {
_prevSelected = null;
} else {
_prevSelected = n;
}
});
} else if (!_prevSelected.isMatch &&
_prevSelected.data == current.data) {
final n = current.copy(showValue: true, isMatch: true);
setState(() {
_matrix[current.x][current.y] = n;
_matrix[_prevSelected.x][_prevSelected.y] = n;
_prevSelected = null;
});
} else if (_prevSelected.data != current.data) {
setState(() {
_matrix[current.x][current.y] = current.copy(
showValue: true
);
});
_scheduleDataVisibilityRemoval(current);
}
}
void _scheduleDataVisibilityRemoval(Position current) async {
await Future.delayed(const Duration(milliseconds: 500));
setState(() {
_matrix[current.x][current.y] = current.copy(
showValue: false,
isMatch: false,
);
_matrix[_prevSelected.x][_prevSelected.y] = _prevSelected.copy(
showValue: false,
isMatch: false,
);
_prevSelected = null;
});
}
@override
void initState() {
super.initState();
_seedMatrix();
}
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: _matrix.map((l) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: l.map((value) {
return GestureDetector(
onTap: value.isMatch ? null : () => _onTap(value),
child: _Circle(
index: value.x + value.y,
isMatch: value.isMatch,
value: value.data.toString(),
showValue: value.showValue,
),
);
}).toList(),
);
}).toList(),
);
}
}
class Position {
final int x;
final int y;
final int data;
final bool showValue;
final bool isMatch;
const Position(this.x, this.y, {
this.data = -1,
this.showValue = false,
this.isMatch = false
});
Position copy({int data, bool showValue, bool isMatch}) {
return Position(
x,
y,
data: data ?? this.data,
showValue: showValue ?? this.showValue,
isMatch: isMatch ?? this.isMatch
);
}
@override
int get hashCode => data.hashCode^ x.hashCode ^ y.hashCode ^
showValue.hashCode ^ isMatch.hashCode;
@override
bool operator ==(o) => o is Position && o.data == data && o.x == x
&& o.y == y && o.showValue == showValue && o.isMatch == isMatch;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment