diff --git a/src/Projects/BKData/Sources/Repository/DefaultOnboardingRepository.swift b/src/Projects/BKData/Sources/Repository/DefaultOnboardingRepository.swift index b6496c7f..655793b6 100644 --- a/src/Projects/BKData/Sources/Repository/DefaultOnboardingRepository.swift +++ b/src/Projects/BKData/Sources/Repository/DefaultOnboardingRepository.swift @@ -21,4 +21,8 @@ public struct DefaultOnboardingRepository: OnboardingRepository { public func saveOnboardingSeen() { try? storage.save(true, for: key) } + + public func resetOnboardingSeen() { + try? storage.save(false, for: key) + } } diff --git a/src/Projects/BKDomain/Sources/Interface/Repository/OnboardingRepository.swift b/src/Projects/BKDomain/Sources/Interface/Repository/OnboardingRepository.swift index be33e735..6d0e41f3 100644 --- a/src/Projects/BKDomain/Sources/Interface/Repository/OnboardingRepository.swift +++ b/src/Projects/BKDomain/Sources/Interface/Repository/OnboardingRepository.swift @@ -3,4 +3,5 @@ public protocol OnboardingRepository { func fetchOnboardingSeen() -> Bool func saveOnboardingSeen() + func resetOnboardingSeen() } diff --git a/src/Projects/BKDomain/Sources/Interface/Usecase/MarkOnboardingSeenUseCase.swift b/src/Projects/BKDomain/Sources/Interface/Usecase/MarkOnboardingSeenUseCase.swift index c1ab52fc..9ab52c6c 100644 --- a/src/Projects/BKDomain/Sources/Interface/Usecase/MarkOnboardingSeenUseCase.swift +++ b/src/Projects/BKDomain/Sources/Interface/Usecase/MarkOnboardingSeenUseCase.swift @@ -4,4 +4,5 @@ import Foundation public protocol MarkOnboardingSeenUseCase { func execute() + func reset() } diff --git a/src/Projects/BKDomain/Sources/UseCase/DefaultMarkOnboardingSeenUseCase.swift b/src/Projects/BKDomain/Sources/UseCase/DefaultMarkOnboardingSeenUseCase.swift index 203b4cc9..a1168581 100644 --- a/src/Projects/BKDomain/Sources/UseCase/DefaultMarkOnboardingSeenUseCase.swift +++ b/src/Projects/BKDomain/Sources/UseCase/DefaultMarkOnboardingSeenUseCase.swift @@ -12,4 +12,8 @@ public struct DefaultMarkOnboardingSeenUseCase: MarkOnboardingSeenUseCase { public func execute() { repository.saveOnboardingSeen() } + + public func reset() { + repository.resetOnboardingSeen() + } } diff --git a/src/Projects/Booket/Sources/DebugOptionViewController.swift b/src/Projects/Booket/Sources/DebugOptionViewController.swift new file mode 100644 index 00000000..a27c772f --- /dev/null +++ b/src/Projects/Booket/Sources/DebugOptionViewController.swift @@ -0,0 +1,138 @@ +// Copyright © 2025 Booket. All rights reserved + +import BKCore +import BKData +import BKDesign +import BKDomain +import BKNetwork +import BKPresentation +import BKStorage +import KakaoSDKAuth +#if DEBUG +import Pulse +import PulseUI +#endif +import SwiftUI +import UIKit + +public final class DebugOptionViewController: UIViewController { + + private struct DebugSection { + let title: String + let options: [DebugOption] + } + + private enum DebugOption: String, CaseIterable { + case showNetworkLog = "네트워크 로그 확인" + case resetOnboardingSeen = "온보딩 화면 보기" + + // 각 옵션에 따라 실행할 함수를 연결 + func performAction(on viewController: UIViewController) { + guard let vc = viewController as? DebugOptionViewController else { return } + switch self { + case .showNetworkLog: + vc.openPulseLog() + case .resetOnboardingSeen: + vc.resetOnboardingSeen() + } + } + } + + private let tableView = UITableView(frame: .zero, style: .insetGrouped) + private var sections: [DebugSection] = [] + + @Autowired var markOnboardingSeenUseCase: MarkOnboardingSeenUseCase + + override public func viewDidLoad() { + super.viewDidLoad() + setupData() + setupUI() + setupTableView() + } + + private func setupData() { + self.sections = [ + DebugSection(title: "Log", options: [ + .showNetworkLog + ]), + DebugSection(title: "플래그 초기화", options: [ + .resetOnboardingSeen + ]) + ] + } + + // UI 설정은 동일 + private func setupUI() { + self.title = "디버그 메뉴" + view.backgroundColor = .systemGroupedBackground + view.addSubview(tableView) + + tableView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), + tableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), + tableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor) + ]) + } + + // 테이블뷰 설정은 동일 + private func setupTableView() { + tableView.delegate = self + tableView.dataSource = self + tableView.register(UITableViewCell.self, forCellReuseIdentifier: "DebugCell") + } + + // 각 셀 선택 시 호출될 함수들 + private func openPulseLog() { + DispatchQueue.main.async { [weak self] in + let viewController = MainViewController() + self?.navigationController?.present(viewController, animated: true) + } + } + + private func resetOnboardingSeen() { + markOnboardingSeenUseCase.reset() + forceQuitApplication() + } + + private func forceQuitApplication() { + UIApplication.shared.perform(#selector(NSXPCConnection.suspend)) + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + exit(0) + } + } +} + +extension DebugOptionViewController: UITableViewDelegate, UITableViewDataSource { + + public func numberOfSections(in tableView: UITableView) -> Int { + return sections.count + } + + public func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + return sections[section].title + } + + public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return sections[section].options.count + } + + public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "DebugCell", for: indexPath) + let option = sections[indexPath.section].options[indexPath.row] + + var content = cell.defaultContentConfiguration() + content.text = option.rawValue + cell.contentConfiguration = content + cell.accessoryType = .none + + return cell + } + + public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + let selectedOption = sections[indexPath.section].options[indexPath.row] + selectedOption.performAction(on: self) + } +} diff --git a/src/Projects/Booket/Sources/SceneDelegate.swift b/src/Projects/Booket/Sources/SceneDelegate.swift index a5e24e77..9bbaf638 100644 --- a/src/Projects/Booket/Sources/SceneDelegate.swift +++ b/src/Projects/Booket/Sources/SceneDelegate.swift @@ -94,7 +94,7 @@ class PulseWindow: UIWindow { super.motionEnded(motion, with: event) guard motion == .motionShake else { return } - let viewController = MainViewController() + let viewController = DebugOptionViewController() let navigation = UINavigationController(rootViewController: viewController) rootViewController?.present(navigation, animated: true) }