Created
April 13, 2023 17:51
-
-
Save haneulee/5c14bacc997ef86d6d04a5738ea2466e to your computer and use it in GitHub Desktop.
flutter pomotimer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'package:flutter/material.dart'; | |
class HomeScreen extends StatefulWidget { | |
const HomeScreen({super.key}); | |
@override | |
State<HomeScreen> createState() => _HomeScreenState(); | |
} | |
class _HomeScreenState extends State<HomeScreen> { | |
static const int breakTime = 5; | |
static const int oneMinToSec = 60; | |
int selectedTime = 15; | |
int totalSeconds = 15 * oneMinToSec; | |
bool isRunning = false; | |
bool isBreaking = false; | |
int round = 0; | |
int goal = 0; | |
late Timer timer; | |
void onTick(Timer timer) { | |
if (totalSeconds == 0) { | |
if (isBreaking) { | |
totalSeconds = selectedTime * oneMinToSec; | |
isBreaking = false; | |
} else { | |
totalSeconds = breakTime * oneMinToSec; | |
isBreaking = true; | |
goal = round == 3 ? ++goal : goal; | |
round = round == 3 ? 0 : ++round; | |
} | |
setState(() { | |
isRunning = false; | |
}); | |
timer.cancel(); | |
} else { | |
setState(() { | |
totalSeconds = totalSeconds - 1; | |
}); | |
} | |
} | |
String format(int seconds, String type) { | |
var duration = Duration(seconds: seconds); | |
var result = | |
duration.toString().split(".").first.substring(2, 7).split(":"); | |
return type == 'min' ? result[0] : result[1]; | |
} | |
void onStartPressed() { | |
timer = Timer.periodic( | |
const Duration(seconds: 1), | |
onTick, | |
); | |
setState(() { | |
isRunning = true; | |
}); | |
} | |
void onPausePressed() { | |
timer.cancel(); | |
setState(() { | |
isRunning = false; | |
}); | |
} | |
void onSelectTime(int time) { | |
if (!isBreaking) { | |
setState(() { | |
selectedTime = time; | |
totalSeconds = selectedTime * oneMinToSec; | |
}); | |
} | |
} | |
void onReset() { | |
setState(() { | |
totalSeconds = selectedTime * oneMinToSec; | |
}); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
backgroundColor: Theme.of(context).colorScheme.background, | |
body: Column( | |
children: [ | |
Flexible( | |
flex: 1, | |
child: Container( | |
alignment: Alignment.centerLeft, | |
margin: const EdgeInsets.only(left: 30), | |
child: Text( | |
'POMOTIMER', | |
style: TextStyle( | |
color: Theme.of(context).cardColor, | |
fontSize: 20, | |
fontWeight: FontWeight.w600, | |
), | |
), | |
), | |
), | |
Flexible( | |
flex: 1, | |
child: Container( | |
alignment: Alignment.bottomCenter, | |
child: Row( | |
mainAxisAlignment: MainAxisAlignment.center, | |
crossAxisAlignment: CrossAxisAlignment.center, | |
children: [ | |
Stack( | |
children: [ | |
Positioned( | |
left: 10, | |
top: 0, | |
child: Container( | |
width: 100, | |
height: 100, | |
color: const Color.fromRGBO(255, 255, 255, 0.5), | |
), | |
), | |
Positioned( | |
left: 5, | |
top: 5, | |
child: Container( | |
width: 110, | |
height: 110, | |
color: const Color.fromRGBO(255, 255, 255, 0.7), | |
), | |
), | |
Container( | |
width: 120, | |
height: 120, | |
margin: const EdgeInsets.only(top: 10), | |
padding: const EdgeInsets.all(5), | |
alignment: Alignment.center, | |
decoration: const BoxDecoration(color: Colors.white), | |
child: Text( | |
format(totalSeconds, "min"), | |
style: TextStyle( | |
color: isBreaking | |
? Colors.green | |
: Theme.of(context).colorScheme.background, | |
fontSize: 70, | |
fontWeight: FontWeight.w600, | |
), | |
), | |
), | |
], | |
), | |
Container( | |
margin: const EdgeInsets.all(10), | |
child: Text( | |
":", | |
style: TextStyle( | |
color: Theme.of(context).cardColor, | |
fontSize: 60, | |
fontWeight: FontWeight.w600, | |
), | |
), | |
), | |
Stack( | |
children: [ | |
Positioned( | |
left: 10, | |
top: 0, | |
child: Container( | |
width: 100, | |
height: 100, | |
color: const Color.fromRGBO(255, 255, 255, 0.5), | |
), | |
), | |
Positioned( | |
left: 5, | |
top: 5, | |
child: Container( | |
width: 110, | |
height: 110, | |
color: const Color.fromRGBO(255, 255, 255, 0.7), | |
), | |
), | |
Container( | |
width: 120, | |
height: 120, | |
margin: const EdgeInsets.only(top: 10), | |
padding: const EdgeInsets.all(5), | |
alignment: Alignment.center, | |
decoration: const BoxDecoration(color: Colors.white), | |
child: Text( | |
format(totalSeconds, "sec"), | |
style: TextStyle( | |
color: isBreaking | |
? Colors.green | |
: Theme.of(context).colorScheme.background, | |
fontSize: 70, | |
fontWeight: FontWeight.w600, | |
), | |
), | |
), | |
], | |
), | |
]), | |
), | |
), | |
SizedBox( | |
height: 100, | |
child: ListView( | |
scrollDirection: Axis.horizontal, | |
padding: const EdgeInsets.only(top: 20), | |
shrinkWrap: true, | |
children: [15, 20, 25, 30, 35].map((time) { | |
return Container( | |
margin: const EdgeInsets.all(10), | |
child: selectedTime == time | |
? TextButton( | |
style: TextButton.styleFrom( | |
foregroundColor: | |
const Color.fromARGB(255, 43, 36, 36), | |
backgroundColor: Colors.white, | |
), | |
onPressed: () => onSelectTime(time), | |
child: Text( | |
time.toString(), | |
style: TextStyle( | |
fontSize: 30, | |
color: Theme.of(context).colorScheme.background, | |
), | |
), | |
) | |
: OutlinedButton( | |
style: OutlinedButton.styleFrom( | |
foregroundColor: | |
const Color.fromARGB(255, 43, 36, 36), | |
backgroundColor: | |
Theme.of(context).colorScheme.background, | |
), | |
onPressed: () => onSelectTime(time), | |
child: Text( | |
time.toString(), | |
style: const TextStyle( | |
fontSize: 30, | |
color: Colors.white, | |
), | |
), | |
), | |
); | |
}).toList(), | |
), | |
), | |
Flexible( | |
flex: 1, | |
child: Center( | |
child: Row( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: [ | |
IconButton( | |
iconSize: 100, | |
color: Theme.of(context).cardColor, | |
onPressed: isRunning ? onPausePressed : onStartPressed, | |
icon: Icon(isRunning | |
? Icons.pause_circle_outline | |
: Icons.play_circle_outline), | |
), | |
IconButton( | |
iconSize: 100, | |
color: Theme.of(context).cardColor, | |
onPressed: onReset, | |
icon: const Icon(Icons.restart_alt_rounded), | |
), | |
], | |
)), | |
), | |
Text( | |
isBreaking ? 'Take a break!' : '', | |
style: const TextStyle( | |
fontSize: 40, color: Colors.green, fontWeight: FontWeight.w600), | |
), | |
Flexible( | |
flex: 1, | |
child: Row( | |
children: [ | |
Expanded( | |
child: Container( | |
decoration: BoxDecoration( | |
color: Theme.of(context).cardColor, | |
borderRadius: BorderRadius.circular(50), | |
), | |
child: Row( | |
crossAxisAlignment: CrossAxisAlignment.center, | |
mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |
children: [ | |
Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: [ | |
Text( | |
'ROUND', | |
style: TextStyle( | |
fontSize: 20, | |
fontWeight: FontWeight.w600, | |
color: | |
Theme.of(context).colorScheme.background, | |
), | |
), | |
Text( | |
'$round/4', | |
style: TextStyle( | |
fontSize: 40, | |
fontWeight: FontWeight.w600, | |
color: | |
Theme.of(context).colorScheme.background, | |
), | |
), | |
], | |
), | |
Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: [ | |
Text( | |
'GOAL', | |
style: TextStyle( | |
fontSize: 20, | |
fontWeight: FontWeight.w600, | |
color: | |
Theme.of(context).colorScheme.background, | |
), | |
), | |
Text( | |
'$goal/12', | |
style: TextStyle( | |
fontSize: 40, | |
fontWeight: FontWeight.w600, | |
color: | |
Theme.of(context).colorScheme.background, | |
), | |
), | |
], | |
), | |
], | |
)), | |
), | |
], | |
), | |
) | |
], | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment