Flutter 공부 6일차

devkwon·2023년 2월 2일
0

뽀모도로 타이머 프로젝트

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:sprintf/sprintf.dart';

enum TimerStatus {running,paused,stopped,resting}

class TimerScreen extends StatefulWidget{
  @override
  _TimerScreenState createState() => _TimerScreenState();
}

class _TimerScreenState extends State<TimerScreen>{
  static const WORK_SECONDS = 3;
  static const REST_SECONDS = 5;

  late TimerStatus _timerStatus;
  late int _timer;
  late int _pomodoroCount;

  @override
  void initState(){
    super.initState();
    _timerStatus = TimerStatus.stopped;
    print(_timerStatus.toString());
    _timer = WORK_SECONDS;
    _pomodoroCount = 0;
  }

  void run(){
    setState(() {
      _timerStatus = TimerStatus.running;
      print("[=>] "+_timerStatus.toString());
      runTimer();
    });
  }

  void rest(){
    setState(() {
      _timer = REST_SECONDS;
      _timerStatus = TimerStatus.resting;
      print("[=>] "+_timerStatus.toString());
    });
  }

  void stop(){
    setState(() {
      _timer = WORK_SECONDS;
      _timerStatus = TimerStatus.stopped;
      print("[=>] $_timerStatus");
    });
  }


  void pause(){
    setState(() {
      _timerStatus = TimerStatus.paused;
      print("[=>] $_timerStatus");
    });
  }

  void resume(){
    setState(() {
      run();
    });
  }

  String secondsToString(int seconds){
    return sprintf("%02d:%02d",[seconds~/60, seconds%60]);
  }

  void runTimer() async{
    Timer.periodic(Duration(seconds: 1), (Timer t){
      switch(_timerStatus){
        case TimerStatus.paused:
          t.cancel();
          break;
        case TimerStatus.stopped:
          t.cancel();
          break;
        case TimerStatus.running:
          if(_timer<=0){
            showToast("작업 완료!");
            rest();
          }
          else{
            setState(() {
              _timer-=1;
            });
          }
          break;
        case TimerStatus.resting:
            if(_timer<=0){
              setState(() {
                _pomodoroCount+=1;
              });
              showToast("오늘 $_pomodoroCount개의 뽀모도로를 달성했습니다.");
              t.cancel();
              stop();
            }
            else{
              setState(() {
                _timer-=1;
              });
            }
            break;
        default:
          break;
      }
    });
  }
  void showToast(String message){
    Fluttertoast.showToast(
      msg: message,
      toastLength: Toast.LENGTH_SHORT,
      gravity: ToastGravity.BOTTOM,
      timeInSecForIosWeb: 5,
      backgroundColor: Colors.grey,
      textColor: Colors.white,
      fontSize: 16.0,
    );
  }
  @override
  Widget build(BuildContext context){
    final List<Widget> _runningButtons =[
      ElevatedButton(
        child: Text(
            _timerStatus==TimerStatus.paused? '계속하기' : '일시정지',
            style: TextStyle(color:Colors.white, fontSize: 16)
        ),
        style: ElevatedButton.styleFrom(primary: Colors.blue),
        onPressed: _timerStatus == TimerStatus.paused ? resume : pause,
      ),
      Padding(padding: EdgeInsets.all(20)),
      ElevatedButton(
        child: Text(
            '포기하기',
            style: TextStyle(fontSize: 16)
        ),
        style: ElevatedButton.styleFrom(primary: Colors.grey),
        onPressed: stop,
      ),
    ];

    final List<Widget> _stoppedButtons = [
      ElevatedButton(
        child: Text(
            '시작하기',
            style: TextStyle(color:Colors.white, fontSize: 16)
        ),
        style: ElevatedButton.styleFrom(
            primary: _timerStatus==TimerStatus.resting? Colors.green : Colors.blue
        ),
        onPressed: run,
      ),
    ];
    return Scaffold(
      appBar: AppBar(
        title: Text('뽀모도로 타이머'),
        backgroundColor: _timerStatus == TimerStatus.running? Colors.green : Colors.blue,
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: [
          Container(
            height: MediaQuery.of(context).size.height*0.5,
            width: MediaQuery.of(context).size.width*0.6,
            child: Center(
              child: Text(
                secondsToString(_timer),
                style: TextStyle(
                  color:Colors.white,
                  fontSize: 48,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
            decoration: BoxDecoration(
              shape: BoxShape.circle,
              color: _timerStatus==TimerStatus.resting? Colors.green : Colors.blue
            ),
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: _timerStatus==TimerStatus.resting? const [] : _timerStatus==TimerStatus.stopped? _stoppedButtons : _runningButtons,
          )
        ],
      ),
    );
  }
}
import 'package:flutter/material.dart';
import 'package:timer/screens/timer_screen.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: TimerScreen(),
    );
  }
}

Timer

Timer.periodic(Duration duration, Timer t)을 사용하면 단위 시간마다 코드를 실행시킬 수 있다.

sprintf

C스타일의 문자열 포맷팅 함수를 지원해주는 외부 패키지,

  String secondsToString(int seconds){
    return sprintf("%02d:%02d",[seconds~/60, seconds%60]);
  }

Toast

화면에 잠시 나타났다가 사라지는 메시지 창

Toast를 구현하기 위해서는 Scaffold와 Context가 필요하다. 하지만 이를 쓸 수 없는 환경이라면 외부 패키지인 fluttertoast를 통해 위 환경을 만족하지 않아도 사용할 수 있다.

void showToast(String message){
    Fluttertoast.showToast(
      msg: message, 
      toastLength: Toast.LENGTH_LONG, // 토스트 시간
      gravity: ToastGravity.BOTTOM, // 위치
      timeInSecForIosWeb: 5, // ios,web 환경에서 토스트 시간
      backgroundColor: Colors.grey,
      textColor: Colors.white,
      fontSize: 16.0,
    );
  }

0개의 댓글