I'm using maze pub package : https://pub.dev/packages/maze. I want to create mini game that will be counting time from opening this screen until getting at the finish line. So I tried to setting timer at the begining, but when I wanted to save this data to share prefs, i got 00:00, instead of time I get displayed on the screen.
class MazeScreen extends StatefulWidget {
const MazeScreen({Key? key}) : super(key: key);
@override
_MazeScreenState createState() => _MazeScreenState();
}
class _MazeScreenState extends State<MazeScreen> {
Duration duration = Duration();
Timer? timer ;
@override
void initState() {
super.initState();
startTimer();
}
void reset() {
setState(() {
timer?.cancel();
});
}
void addTime() {
const addSeconds = 1;
setState(() {
final seconds = duration.inSeconds addSeconds;
duration = Duration(seconds: seconds);
});
}
void startTimer() {
timer = Timer.periodic(Duration(seconds: 1), (_) => addTime());
}
@override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
String twoDigits(int n) => n.toString().padLeft(2, '0');
final minutes = twoDigits(duration.inMinutes.remainder(60));
final seconds = twoDigits(duration.inSeconds.remainder(60));
return Scaffold(
body: Stack(children: <Widget>[
Container(
// Here the height of the container is 45% of our total height
height: size.height * .35,
decoration: const BoxDecoration(
color: Color(0xFF3d405b),
),
),
SafeArea(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
MemoryCard("time", "$minutes:$seconds"),
],
),
Expanded(
flex: 2,
child: Container(
alignment: AlignmentDirectional.center,
padding: const EdgeInsets.all(10.0),
child: const Text(
'Maze game',
style: TextStyle(
color: Color(0xFFe07a5f),
fontSize: 25.0,
fontStyle: FontStyle.italic,
),
),
),
),
Expanded(
flex: 9,
child: Stack(
children: [
Container(
margin: const EdgeInsets.symmetric(vertical: 20.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16.0),
color: const Color(0xFFf4f1de),
),
),
Maze(
player: MazeItem(
'assets/start.png',
ImageType.asset,
),
columns: 7,
rows: 7,
wallThickness: 3.0,
wallColor: const Color(0xFF81b29a),
finish: MazeItem(
'assets/finish.png',
ImageType.asset,
),
onFinish: () async {
reset();
final prefs = await SharedPreferences.getInstance();
await prefs.setString("mazeTimer", '$minutes:$seconds');
},
),
],
),
),
],
),
),
),
]),
);
}
}
When I do it like that I receive 00:00.
CodePudding user response:
You would need to handle minute / second
in the state as variables like you handle duration
, which is where they belong as they represent a state.
Calculate them every time duration
gets updated. These calculated values can then be displayed or used in this call:
await prefs.setString("mazeTimer", ... );
The reason 00:00
gets saved is that the function onFinish: ()
gets initialized once at the beginning, when when the final
values of minute and second are actually 00:00
.
Try something like this:
class _MazeScreenState extends State<MazeScreen> {
Duration duration = Duration();
Timer? timer ;
String minutes = '00'; // it may be better to store an int, not a String
String seconds = '00'; // it may be better to store an int, not a String
...
void addTime() {
const addSeconds = 1;
setState(() {
final seconds = duration.inSeconds addSeconds;
duration = Duration(seconds: seconds);
minutes = ... // ADD CALCULATION HERE
seconds = ... // ADD CALCULATION HERE
});
}
}
A second approach would be to calculate minutes and seconds here, but you would end up with having minutes / seconds
multiple times in the code, which is redundant:
onFinish: () async {
reset();
final prefs = await SharedPreferences.getInstance();
final min = ... // CALCULATE HERE
final sec= ... // CALCULATE HERE
await prefs.setString("mazeTimer", '$min:$sec');
}