Skip to content

파스타의 종류에 따라 익혀야할 시간을 알려주는 파스타 타이머입니다

Notifications You must be signed in to change notification settings

thisisthewa2/OnePagePastaTimer

Repository files navigation

OnePagePastaTimer

파스타의 종류에 따라 익혀야할 시간을 알려주는 파스타 타이머

  • 실행 화면

Simulator Screen Recording - iPhone 14 Pro - 2023-04-06 at 15 58 53

  • 메인화면 코드
import SwiftUI
class EnvironmentViewModel : ObservableObject{
    @Published var title: [String] = []
    @Published var time: [Int] = [] //조리시간
    @Published var isClicked: [Bool] = [] //클릭여부
    @Published var backgroundColor: [Color] = []
    @Published var rightIndex: Int = 0
    //클릭여부에 따른 배경색상
    
    init() {
        getData()
    }
    
    func getData() {
        title.append(contentsOf: [" 토마토 \n 파스타"," 알리오 \n 올리오"," 상하이 \n 파스타"])
        time.append(contentsOf: [540,700,600])
        isClicked.append(contentsOf: [false, false, false])
        backgroundColor.append(contentsOf: [Color("greenbutton"), Color("greenbutton"), Color("greenbutton")])
    }
}

struct MainView: View {
    
    @StateObject var viewModel: EnvironmentViewModel = EnvironmentViewModel()
    
    
    var body: some View {
        ZStack {
            
            Color("background")
                .ignoresSafeArea()
            VStack(spacing:50) {
                HStack(spacing:20){
                    ForEach(viewModel.title.indices, id: \.self) { index in
                        Button(action: {
                            //다른 모든 버튼이 선택되지 않았을 때만 참이 되는 변수
                            let allOtherButtonsNotClicked = self.viewModel.isClicked.filter { $0 }.count == 0
                            if allOtherButtonsNotClicked || self.viewModel.isClicked[index] {
                                self.viewModel.isClicked[index].toggle()
                                if self.viewModel.isClicked[index] {
                                    self.viewModel.backgroundColor[index] = Color("pink")
                                    self.viewModel.rightIndex = index
                                } else {
                                    self.viewModel.backgroundColor[index] = Color("greenbutton")
                                }
                            }
                        }, label: {
                            Text("\(self.viewModel.title[index])")
                                .frame(width: 100, height: 100)
                                .background(self.viewModel.backgroundColor[index])
                                .foregroundColor(Color("outline"))
                                .clipShape(Circle())
                                .overlay(
                                    RoundedRectangle(cornerRadius: 50)
                                        .stroke(Color("outline"), lineWidth: 2)
                                )
                        })
                    }
                }
                Spacer(minLength: 100)
                if !self.viewModel.isClicked[0] && !self.viewModel.isClicked[1] && !self.viewModel.isClicked[2]{
                    Text("파스타를\n선택하세요")
                        .font(.system(size: 50, weight: .regular))
                        .fontWeight(.bold)
                        .multilineTextAlignment(.center)
                        .foregroundColor(Color("outline"))
                    Spacer(minLength: 280)
                }
                else{
                    TimerView(viewModel: viewModel)

                }
                
                
            }
        }
    }
    
}
  • 타이머 화면 코드
import SwiftUI
struct TimerView: View {
    @ObservedObject var viewModel: EnvironmentViewModel //주석 1 참고
    @State var secondsLeft: Int = 0
    @State var timer: Timer?
    @State var isTimerActive: Bool = false //타이머를 활성화하는 변수
    var timeLimit: Int = 100
    var selectedIndex: Int = 0 { //선택된 파스타 버튼의 인덱스
    didSet {
                    // selectedIndex가 바뀌면 초기화
                    self.secondsLeft = viewModel.time[selectedIndex]
                    self.timeLimit = viewModel.time[selectedIndex]
                    self.timer?.invalidate()
                    self.isTimerActive = false
                }
    }

    init(viewModel: EnvironmentViewModel) {
        //viewModel을 인자로 받아 초기화
                self.viewModel = viewModel //주석 1: StateObject로 받으면 self.~으로 초기화할 수 없어서 ObservedObject로 선언
                self.selectedIndex = viewModel.isClicked.firstIndex(of: true) ?? 0
                _secondsLeft = State(initialValue: viewModel.time[selectedIndex])
                timeLimit = viewModel.time[selectedIndex]
            }
    
    var body: some View{
        VStack{
            Text("\(secondsLeftToMinutesSeconds(seconds:secondsLeft))")
                .font(.system(size: 64, weight: .semibold))
                .foregroundColor(Color("outline"))
                .multilineTextAlignment(.center)
            Spacer()
            HStack(spacing:16){
                Button(action: {
                    self.secondsLeft = timeLimit
                    isTimerActive = false
                }){
                    Image("resetIcon")
                        .resizable()
                        .frame(width: 22.0, height: 22.0)
                }.buttonStyle(SubButton())
                
                Button(action: {
                    if !isTimerActive {
                        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
                            if secondsLeft > 0 {
                                secondsLeft -= 1
                            } else {
                                //0초 이하의 시간이 남았다면 멈춤
                                timer?.invalidate()
                                isTimerActive = false
                            }
                        }
                        isTimerActive = true
                    }
                }){
                   Image("startIcon")
                        .resizable()
                        .frame(width: 22.0, height: 22.0)
                }.buttonStyle(StartButton())
                
                Button(action: {
                    // 타이머 멈춤
                    timer?.invalidate()
                    isTimerActive = false
                }) {
                    Image("pauseIcon")
                        .resizable()
                        .frame(width: 22.0, height: 22.0)
                }.buttonStyle(SubButton())
            }
        }
    }
    //초를 받아 분:초 스트링으로 바꿔 변환
            func secondsLeftToMinutesSeconds(seconds: Int) -> String {
                let minutes = (seconds % 3600) / 60
                let seconds = (seconds % 3600) % 60
                return String(format: "%02d:%02d", minutes, seconds)
            }
            
        }


//버튼 스타일
struct StartButton: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .frame(width: 128, height: 96)
            .foregroundColor(Color.black)
            .background(Color("pink"))
            .cornerRadius(32)
        
        
    }
}

struct SubButton: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
    configuration.label
        .frame(width: 80, height: 80)
        .foregroundColor(Color.black)
        .background(Color("lightpink"))
        .cornerRadius(24)
        
        
}
}

  • 어려웠던 점 & 새로 배운 점
  1. ViewModel과 멀티뷰에서 하나의 객체에 접근하는 방법에 대해 알게 되었다.

다른 파스타 유형을 선택했을 때, 즉 데이터가 변경되었을 때 파스타 유형에 맞는 타이머 시간을 설정하기 위하여 ViewModel을 처음 사용해보았다. EnvironmentViewModel(ObservableObject): @Published var -> MainView: @StateObject -> TimerView: @ObservedObject를 MainView에서 인자로 전달한 viewModel로 초기화 를 사용하여 MainView에서 데이터가 바뀐 경우 TimerView 화면을 다시 그리도록 설정했다. 더 효율적인 방법이 있을 것 같은데 리팩토링을 통해 개선해보고 싶다.

  1. filter 함수의 사용법을 새로 배웠다.

한 번에 두 개의 파스타 유형이 선택되지 않도록 하기 위해 filter함수를 아래와 같이 사용했다.

ForEach(viewModel.title.indices, id: \.self) { index in
                        Button(action: {
                            //다른 모든 버튼이 선택되지 않았을 때만 참이 되는 변수
                            let allOtherButtonsNotClicked = self.viewModel.isClicked.filter { $0 }.count == 0
                            if allOtherButtonsNotClicked || self.viewModel.isClicked[index] {
                                self.viewModel.isClicked[index].toggle()
                                if self.viewModel.isClicked[index] {
                                    self.viewModel.backgroundColor[index] = Color("pink")
                                    self.viewModel.rightIndex = index
                                } else {
                                    self.viewModel.backgroundColor[index] = Color("greenbutton")
                                }
                            }
                        },
  1. 타이머 클래스 메서드를 처음 사용해보았다.

아래에서처럼 1초 간격의 타이머가 0초 이하의 시간이 남았다거나 정지 버튼을 누르는 경우 멈추도록 하였다. 그리고 리셋버튼을 사용하는 경우 타이머 시간을 초기화하도록 작성해보았다.

 HStack(spacing:16){
               Button(action: {
                   self.secondsLeft = timeLimit
                   isTimerActive = false
               }){
                   Image("resetIcon")
                       .resizable()
                       .frame(width: 22.0, height: 22.0)
               }.buttonStyle(SubButton())
               
               Button(action: {
                   if !isTimerActive {
                       timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
                           if secondsLeft > 0 {
                               secondsLeft -= 1
                           } else {
                               //0초 이하의 시간이 남았다면 멈춤
                               timer?.invalidate()
                               isTimerActive = false
                           }
                       }
                       isTimerActive = true
                   }
               }){
                  Image("startIcon")
                       .resizable()
                       .frame(width: 22.0, height: 22.0)
               }.buttonStyle(StartButton())
               
               Button(action: {
                   // 타이머 멈춤
                   timer?.invalidate()
                   isTimerActive = false
               }) {
                   Image("pauseIcon")
                       .resizable()
                       .frame(width: 22.0, height: 22.0)
               }.buttonStyle(SubButton())
           }

About

파스타의 종류에 따라 익혀야할 시간을 알려주는 파스타 타이머입니다

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages