Skip to content

Commit

Permalink
Merge pull request #44 from APPSCHOOL3-iOS/feature/timer.ver4
Browse files Browse the repository at this point in the history
feat: timerview 디자인수정과 기능 구현 #43
  • Loading branch information
YeoSungeun authored Oct 12, 2023
2 parents f0d4a13 + aa64c47 commit 6b04d57
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 113 deletions.
17 changes: 13 additions & 4 deletions Pickle/Pickle/Screen/Home/TimerReportView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ struct TimerReportView: View {

@Environment(\.dismiss) private var dismiss

@Binding var isShowingReportSheet: Bool
@Binding var isComplete: Bool
@Binding var isShowingTimerView: Bool

var todo: Todo
var spendTime: Int
var spendTime: TimeInterval

var body: some View {
VStack {
Expand All @@ -30,7 +34,7 @@ struct TimerReportView: View {
HStack {
Text("총 소요 시간")
Spacer()
Text(convertSecondsToTime(timeInSecond: spendTime))
Text(convertSecondsToTime(timeInSecond: Int(spendTime)))
}
}
.font(.pizzaTitle2Bold)
Expand Down Expand Up @@ -71,11 +75,16 @@ struct TimerReportView: View {
}

Button(action: {

isShowingTimerView = false
isShowingReportSheet = false
dismiss()
}, label: {
Text("확인")
})
}
.onAppear {
isComplete = true
}
}
func convertSecondsToTime(timeInSecond: Int) -> String {
let hours = timeInSecond / 3600 // 시
Expand All @@ -92,7 +101,7 @@ struct TimerReportView: View {

struct TimerReportView_Previews: PreviewProvider {
static var previews: some View {
TimerReportView(todo: Todo(id: UUID().uuidString,
TimerReportView(isShowingReportSheet: .constant(false), isComplete: .constant(false), isShowingTimerView: .constant(false), todo: Todo(id: UUID().uuidString,
content: "이력서 작성하기",
startTime: Date(),
targetTime: 60,
Expand Down
244 changes: 138 additions & 106 deletions Pickle/Pickle/Screen/Home/TimerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,163 +13,184 @@ struct TimerView: View {
var todo: Todo
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

@State var targetTime: TimeInterval = 1 // 목표소요시간
@State var timeRemaining: TimeInterval = 0 // 남은 시간
@State var spendTime: TimeInterval = 0 // 실제 소요시간
@State var timeExtra: TimeInterval = 0 // 추가소요시간
@State var settingTime: TimeInterval = 0 // 원형 타이머 설정용 시간
@State private var targetTime: TimeInterval = 1 // 목표소요시간
@State private var timeRemaining: TimeInterval = 0 // 남은 시간
@State private var spendTime: TimeInterval = 0 // 실제 소요시간
@State private var timeExtra: TimeInterval = 0 // 추가소요시간
@State private var settingTime: TimeInterval = 0 // 원형 타이머 설정용 시간
@State private var completeLimit: TimeInterval = 10 // 5분 이후
@State private var isDisabled: Bool = true // 완료버튼 활성화 용도

@State var isShowGiveupAlert: Bool = false
@State var isDecresing: Bool = true
@State var isStart: Bool = true
@State private var isGiveupSign: Bool = false
@State private var isShowGiveupAlert: Bool = false
@State private var isDecresing: Bool = true
@State private var isStart: Bool = true
@State private var isShowingReportSheet: Bool = false
@State private var isComplete: Bool = false // '완료'버튼 누를때 시간 멈추기 확인용
@Binding var isShowingTimerView: Bool

var body: some View {
VStack {
// TODO: RegisterView처럼 랜덤으로 바꿔주기
// 멘트부분
if isStart {
Text("따라 읽어봐요!")
.font(Font.pizzaTitleBold)
.padding(.top)
.padding(.bottom, 50)

Text("")
.foregroundColor(.secondary)
.padding(.top, 10)
.padding(.bottom, 40)
} else {
Text("시작이 반이다! 시작했네유~")
Text(todo.content)
.font(Font.pizzaTitleBold)
.padding(.top)
.padding(.bottom, 50)

// TODO: RegisterView처럼 랜덤으로 바꿔주기
Text("🍕 굽는 중")
.foregroundColor(.secondary)
.padding(.top, 10)
.padding(.bottom, 40)
}
// 타이머 부분
// MARK: 타이머 부분
ZStack {
Circle()
.fill(Color.lightGray)
.fill(.clear)
.frame(width: CGFloat.screenWidth * 0.75)
.overlay(Circle().stroke(Color.defaultGray, lineWidth: 20))
.overlay(Circle().stroke(.tertiary, lineWidth: 5))
Circle()
.trim(from: 0, to: progress())
.stroke(Color.black, style: StrokeStyle(lineWidth: 19, lineCap: .round))
.stroke(Color.primary, style: StrokeStyle(lineWidth: 5, lineCap: .round))
.frame(width: CGFloat.screenWidth * 0.75)
.rotationEffect(.degrees(-90))
VStack {
if isStart {
if timeRemaining != 0 {
Text(String(format: "%g", timeRemaining))
.font(Font.system(size: 40))
.fontWeight(.heavy)
.onReceive(timer) { _ in
timeRemaining -= 1
}
} else {
Text("시작")
.font(Font.system(size: 40))
.fontWeight(.heavy)
.onReceive(timer) { _ in
calcRemain()
}
}

if isStart {
if timeRemaining != 0 {
Text(String(format: "%g", timeRemaining))
.font(Font.system(size: 40))
.fontWeight(.heavy)
.onReceive(timer) { _ in
timeRemaining -= 1
}
} else {
Image("smilePizza")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: CGFloat.screenWidth * 0.5)

if isDecresing {
// 남은시간 줄어드는 타이머
Text(convertSecondsToTime(timeInSecond: timeRemaining))
.font(Font.pizzaTitleBold)
.onReceive(timer) { _ in
Text("시작")
.font(Font.system(size: 40))
.fontWeight(.heavy)
.onReceive(timer) { _ in
calcRemain()
}
}
} else {

if isDecresing {
// 남은시간 줄어드는 타이머
Text(convertSecondsToTime(timeInSecond: timeRemaining))
.font(Font.pizzaTitleBold)
.onReceive(timer) { _ in
if !isComplete {
timeRemaining -= 1
spendTime += 1
if timeRemaining == 0 {
turnMode()
}
if spendTime >= completeLimit {
isDisabled = false
}
}
} else {
// 추가시간 늘어나는 타이머
HStack {
Text("+ \(convertSecondsToTime(timeInSecond: timeExtra))")
.font(Font.pizzaTitleBold)
.onReceive(timer) { _ in
}
} else {
// 추가시간 늘어나는 타이머
HStack {
Text("+ \(convertSecondsToTime(timeInSecond: timeExtra))")
.font(Font.pizzaTitleBold)
.onReceive(timer) { _ in
if !isStart && !isComplete {
timeExtra += 1
if timeExtra.truncatingRemainder(dividingBy: 600) == 0 {
turnMode()
}
spendTime += 1
}
}
}
}

// 실제 소요시간 타이머
Text(convertSecondsToTime(timeInSecond: spendTime))
.foregroundColor(Color.textGray)
.onReceive(timer) { _ in
spendTime += 1
}
}

// 목표시간 명시
Text(convertTargetTimeToString(timeInSecond: todo.targetTime))
.foregroundColor(.secondary)
.offset(y: 40)
}
}
// 완료, 포기 버튼
// MARK: 완료, 포기 버튼
HStack {
NavigationLink {
// TimerReportView Sheet 로 하기
Button {
// TODO: spendTime 업데이트하기
TimerReportView(todo: todo, spendTime: Int(spendTime))
if isDisabled {
isShowGiveupAlert = true
isComplete = true
} else {
isShowingReportSheet = true
isComplete = true
}
} label: {
Image(systemName: "checkmark.seal")

Text("완료")
.font(.pizzaHeadlineBold)
.frame(width: 75, height: 75)
.foregroundColor(.green)
.background(Color(hex: 0xDAFFD9))
.clipShape(Circle())
}
.padding([.leading, .trailing], 75)

Button(action: {
// 포기 alert띄우기
isGiveupSign = true
isShowGiveupAlert = true
}, label: {
HStack {
Image(systemName: "trash.fill")
Text("포기")
}
Text("포기")
.font(.pizzaHeadlineBold)
.frame(width: 75, height: 75)
.foregroundColor(.red)
.background(Color(hex: 0xFFDBDB))
.clipShape(Circle())

})
.padding([.leading, .trailing], 75)

}
.buttonStyle(.bordered)
.tint(Color.black)
.padding(.top, 10)

// 지금 하는 일
HStack {
VStack(alignment: .leading) {
Text(todo.content)
.font(Font.pizzaHeadline)
.padding(.bottom)
// TODO: 날짜 불러오기 date extension
Text("오후 5:00")
.font(Font.pizzaFootnote)
}
Spacer()
}
.padding()
.background(Color.lightGray)
.cornerRadius(15)
.padding([.leading, .trailing, .top], 30)

Spacer()
}
.onAppear {
startTodo()
}
.navigationBarBackButtonHidden(true)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button {
.alert(isPresented: $isShowGiveupAlert) {
if isDisabled && !isGiveupSign {
Alert(title: Text("시작 후 5분은 피자조각을 얻지 못해요"),
message: Text(""),
primaryButton: .destructive(Text("완료")) {
// 포기하기 함수
isShowGiveupAlert = true
isShowingReportSheet = true
}, secondaryButton: .cancel(Text("취소")) {
isComplete = false
})

} else {
Alert(title: Text("정말 포기하시겠습니까?"),
message: Text("지금 포기하면 피자조각을 얻지 못해요"),
primaryButton: .destructive(Text("포기하기")) {
// 포기하기 함수
dismiss()
} label: {
Image(systemName: "chevron.backward")
}

}, secondaryButton: .cancel(Text("취소")) {
isGiveupSign = false
})
}
}
.alert(isPresented: $isShowGiveupAlert) {
Alert(title: Text("정말 포기하시겠습니까?"),
message: Text("지금 포기하면 피자조각을 얻지 못해요"),
primaryButton: .destructive(Text("포기하기")) {
// 포기하기 함수
dismiss()
}, secondaryButton: .cancel(Text("취소")))
// TimerReportView Sheet로!
.sheet(isPresented: $isShowingReportSheet) {
TimerReportView(isShowingReportSheet: $isShowingReportSheet, isComplete: $isComplete, isShowingTimerView: $isShowingTimerView, todo: todo, spendTime: spendTime)
}
}

Expand All @@ -187,6 +208,18 @@ struct TimerView: View {
}
}

// 목표시간 초 -> H시간 M분으로 보여주기
func convertTargetTimeToString(timeInSecond: TimeInterval) -> String {
let hours: Int = Int(timeInSecond / 3600)
let minutes: Int = Int(timeInSecond - Double(hours) * 3600) / 60

if timeInSecond >= 3600 {
return String(format: "%i시간 %i분", hours, minutes)
} else {
return String(format: "%i분", minutes)
}
}

func startTodo() {
self.settingTime = 3
self.timeRemaining = settingTime
Expand All @@ -197,24 +230,23 @@ struct TimerView: View {
func calcRemain() {
isStart = false
// TODO: targetTime 초? or 분?
// TODO: 여기서 시작시간 update
self.settingTime = todo.targetTime
self.timeRemaining = settingTime
}

func turnMode() {
self.isDecresing = false
self.settingTime = 600
}



func progress() -> CGFloat {
if isStart {
return CGFloat(0)
} else {
if isDecresing {
return (CGFloat(settingTime - timeRemaining) / CGFloat(settingTime))
} else {
return (CGFloat(timeExtra.truncatingRemainder(dividingBy: 60)) / CGFloat(settingTime))
return 1
}
}
}
Expand All @@ -228,7 +260,7 @@ struct TimerView_Previews: PreviewProvider {
startTime: Date(),
targetTime: 60,
spendTime: Date() + 5400,
status: .ready))
status: .ready), isShowingTimerView: .constant(false))
}
}
}
Loading

0 comments on commit 6b04d57

Please sign in to comment.