diff --git a/JLPTVoca/JLPTVoca/Managers/HapticManager.swift b/JLPTVoca/JLPTVoca/Managers/HapticManager.swift new file mode 100644 index 0000000..eab870e --- /dev/null +++ b/JLPTVoca/JLPTVoca/Managers/HapticManager.swift @@ -0,0 +1,23 @@ +// +// HapticManager.swift +// JLPTVoca +// +// Created by Rama on 9/1/25. +// + +import UIKit + +class HapticManager { + static let instance = HapticManager() + private init() {} + + func notification(type: UINotificationFeedbackGenerator.FeedbackType) { + let generator = UINotificationFeedbackGenerator() + generator.notificationOccurred(type) + } + + func impact(style: UIImpactFeedbackGenerator.FeedbackStyle) { + let generator = UIImpactFeedbackGenerator(style: style) + generator.impactOccurred() + } +} diff --git a/JLPTVoca/JLPTVoca/Views/WordCardView.swift b/JLPTVoca/JLPTVoca/Views/WordCardView.swift index 1c5f059..e5c4e2e 100644 --- a/JLPTVoca/JLPTVoca/Views/WordCardView.swift +++ b/JLPTVoca/JLPTVoca/Views/WordCardView.swift @@ -33,6 +33,8 @@ struct WordCardView: View { let drag = DragGesture() .onChanged { offset = $0.translation } .onEnded { + HapticManager.instance.notification(type: .success) + if $0.translation.width < -100 { //TODO: RawVal 수정 offset = .init(width: -1000, height: 0) swiped(id, .left) diff --git a/JLPTVoca/JLPTVoca/Views/WordStudyView.swift b/JLPTVoca/JLPTVoca/Views/WordStudyView.swift index 6d0dd2f..30bc262 100644 --- a/JLPTVoca/JLPTVoca/Views/WordStudyView.swift +++ b/JLPTVoca/JLPTVoca/Views/WordStudyView.swift @@ -10,8 +10,42 @@ import SwiftUI struct WordStudyView: View { @Environment(WordManager.self) private var wordManager + @Environment(NavigationManager.self) private var router + + @State private var showAlert = false + @State private var showCompletionModal = false var body: some View { + ZStack { + VStack { + wordDeckView() + } + + if showCompletionModal { + studyCompletionView() + } + } + .navigationBarBackButtonHidden(true) + .toolbar(.hidden, for: .tabBar) + .toolbar { customBackButton() } + .alert( + "학습 종료", + isPresented: $showAlert, + actions: { + alertButtons + }, message: { + Text("7년 연습생 하고 집에 갈래?") //TODO: RawVal 수정 + }) + .onChange(of: wordManager.wordDeck) { _, newDeck in + if newDeck.isEmpty { + showCompletionModal = true + } + } + } +} + +extension WordStudyView { + private func wordDeckView() -> some View { ZStack { ForEach(wordManager.wordDeck) { word in WordCardView( @@ -28,8 +62,36 @@ struct WordStudyView: View { } } } -} - -#Preview { - WordStudyView() + + private func studyCompletionView()-> some View { + ZStack { + Color.black.opacity(0.5) + .ignoresSafeArea() + + Button(action: { + router.path.removeLast() + }) { + Text("홈으로 돌아가기") + } + } + } + + @ToolbarContentBuilder + private func customBackButton() -> some ToolbarContent { + ToolbarItem(placement: .navigationBarLeading) { + Button { + showAlert = true + } label: { + Image(systemName: "chevron.backward") + } + } + } + + @ViewBuilder + private var alertButtons: some View { + Button("취소", role: .cancel) { } + Button("종료", role: .destructive) { + router.pop() + } + } }