Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ extension UIViewController {
case withBackButton(title: String) // 백버튼 + 타이틀 (없으면 빈 String)
case withTitle(title: String) // 오로지 타이틀만
case withProgressBar(step: Int) // 백버튼 + progress
case withRightButton(
title: String,
rightButtonImage: UIImage,
rightButtonAction: UIAction,
rightButtonTintColor: UIColor? = nil,
withBackButton: Bool = false) // 커스텀 우측 버튼
}

func configureCustomNavigationBar(navigationBarStyle: NavigationBarStyle, backgroundColor: UIColor? = .white) {
Expand All @@ -31,6 +37,7 @@ extension UIViewController {
private func customNavigationBar(navigationBarStyle: NavigationBarStyle) -> UIView {
let navigationBar = UIView()
let customBackButton = UIButton()
let customRightButton = UIButton()
let titleLabel = UILabel()
let progressView = UIImageView()

Expand All @@ -46,6 +53,7 @@ extension UIViewController {
titleLabel.textColor = BitnagilColor.gray10

progressView.isHidden = true
customRightButton.isHidden = true

switch navigationBarStyle {
case .withBackButton(let title):
Expand All @@ -59,10 +67,23 @@ extension UIViewController {
titleLabel.isHidden = true
progressView.image = progressImage(step: step)
progressView.isHidden = false
case .withRightButton(
title: let title,
rightButtonImage: let rightButtonImage,
rightButtonAction: let action,
rightButtonTintColor: let tintColor,
withBackButton: let withBackButton):

customBackButton.isHidden = !withBackButton
customRightButton.isHidden = false
customRightButton.addAction(action, for: .touchUpInside)
titleLabel.text = title
customRightButton.setImage(rightButtonImage, for: .normal)
customRightButton.tintColor = tintColor
}

navigationBar.backgroundColor = .systemBackground
[customBackButton, titleLabel, progressView].forEach {
[customBackButton, titleLabel, progressView, customRightButton].forEach {
navigationBar.addSubview($0)
}

Expand All @@ -72,6 +93,12 @@ extension UIViewController {
make.size.equalTo(48)
}

customRightButton.snp.makeConstraints { make in
make.top.equalToSuperview()
make.trailing.equalToSuperview()
make.size.equalTo(48)
}

titleLabel.snp.makeConstraints { make in
make.center.equalToSuperview()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,16 +121,16 @@ public struct PresentationDependencyAssembler: DependencyAssemblerProtocol {
return WithdrawViewModel(authRepository: authRepository)
}

DIContainer.shared.register(type: ReportViewModel.self) { container in
DIContainer.shared.register(type: ReportRegistrationViewModel.self) { container in
guard let reportUseCase = container.resolve(type: ReportUseCaseProtocol.self)
else { fatalError("reportUseCase 의존성이 등록되지 않았습니다.") }

return ReportViewModel(reportUseCase: reportUseCase)
return ReportRegistrationViewModel(reportUseCase: reportUseCase)
}

DIContainer.shared
.register(type: ReportListHistoryViewModel.self) { container in
return ReportListHistoryViewModel()
.register(type: ReportHistoryViewModel.self) { container in
return ReportHistoryViewModel()
}

DIContainer.shared.register(type: ReportDetailViewModel.self) { container in
Expand Down
67 changes: 34 additions & 33 deletions Projects/Presentation/Sources/MyPage/View/MypageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ final class MypageView: BaseViewController<MypageViewModel> {
private enum Layout {
static let profileImageViewSize: CGFloat = 80
static let profileImageViewCornerRadius: CGFloat = profileImageViewSize / 2
static let profileImageViewTopSpacing: CGFloat = 32
static let profileImageViewTopSpacing: CGFloat = 74
static let nicknameLabelHeight: CGFloat = 24
static let nicknameLabelTopSpacing: CGFloat = 12
static let divideLineHeight: CGFloat = 6
Expand All @@ -41,28 +41,12 @@ final class MypageView: BaseViewController<MypageViewModel> {

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

navigationController?.setNavigationBarHidden(false, animated: animated)

let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = .white
appearance.shadowColor = .clear

navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance
navigationController?.navigationBar.compactAppearance = appearance
navigationController?.navigationBar.isHidden = false
navigationController?.navigationBar.isHidden = true
}

override func configureAttribute() {
view.backgroundColor = .white
navigationItem.rightBarButtonItem = settingButton
title = "마이페이지"

settingButton.action = #selector(settingButtonTapped)
settingButton.target = self
settingButton.image = BitnagilIcon.settingIcon?.withRenderingMode(.alwaysOriginal)
profileImageView.image = BitnagilGraphic.profileGraphic

nicknameLabel.font = BitnagilFont(style: .title3, weight: .semiBold).font
Expand All @@ -76,6 +60,21 @@ final class MypageView: BaseViewController<MypageViewModel> {
tableView.delegate = self
tableView.separatorStyle = .none
tableView.bounces = false

let settingButtonImage = BitnagilIcon.settingIcon
let settingButtonAction = UIAction { [weak self] _ in
guard let settingViewModel = Shared.DIContainer.shared.resolve(type: SettingViewModel.self) else { return }
let settingView = SettingView(viewModel: settingViewModel)
self?.navigationController?.pushViewController(settingView, animated: true)
}

configureCustomNavigationBar(navigationBarStyle:
.withRightButton(
title: "마이페이지",
rightButtonImage: settingButtonImage ?? .init(),
rightButtonAction: settingButtonAction,
rightButtonTintColor: BitnagilColor.gray70,
withBackButton: false))
}

override func configureLayout() {
Expand Down Expand Up @@ -126,12 +125,6 @@ final class MypageView: BaseViewController<MypageViewModel> {
}
.store(in: &cancellables)
}

@objc private func settingButtonTapped() {
guard let settingViewModel = Shared.DIContainer.shared.resolve(type: SettingViewModel.self) else { return }
let settingView = SettingView(viewModel: settingViewModel)
navigationController?.pushViewController(settingView, animated: true)
}
}

extension MypageView: UITableViewDelegate {
Expand Down Expand Up @@ -165,16 +158,24 @@ extension MypageView: UITableViewDataSource {

let selectedMenu = MypageViewModel.MypageMenu.allCases[indexPath.row]

guard selectedMenu == .resetGoal else {
viewModel.action(input: .didSelectMenu(menu: selectedMenu))
return
}
switch selectedMenu {

guard let onboardingViewModel = DIContainer.shared.resolve(type: OnboardingViewModel.self)
else { fatalError("onboardingViewModel 의존성이 등록되지 않았습니다.") }
case .reportHistory:
guard let reportHistoryViewModel = DIContainer.shared.resolve(type: ReportHistoryViewModel.self)
else { fatalError("reportHistoryViewModel 의존성이 등록되지 않았습니다.") }

let onboardingView = OnboardingResultViewController(viewModel: onboardingViewModel, entryPoint: .myPagePrevious)
onboardingView.hidesBottomBarWhenPushed = true
navigationController?.pushViewController(onboardingView, animated: true)
let reportHistoryViewController = ReportHistoryViewController(viewModel: reportHistoryViewModel)
reportHistoryViewController.hidesBottomBarWhenPushed = true
navigationController?.pushViewController(reportHistoryViewController, animated: true)
case .resetGoal:
guard let onboardingViewModel = DIContainer.shared.resolve(type: OnboardingViewModel.self)
else { fatalError("onboardingViewModel 의존성이 등록되지 않았습니다.") }

let onboardingView = OnboardingResultViewController(viewModel: onboardingViewModel, entryPoint: .myPagePrevious)
onboardingView.hidesBottomBarWhenPushed = true
navigationController?.pushViewController(onboardingView, animated: true)
case .notice, .faq:
viewModel.action(input: .didSelectMenu(menu: selectedMenu))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ final class MypageViewModel: ViewModel {
}

enum MypageMenu: String, CaseIterable {
case reportHistory = "내 제보 기록"
case resetGoal = "내 목표 재설정"
case notice = "공지사항"
case faq = "자주 묻는 질문"
Expand Down Expand Up @@ -67,6 +68,8 @@ final class MypageViewModel: ViewModel {
if let url = URL(string: "https://complex-wombat-99f.notion.site/23ff4587491d80659ae3ea392afbc05e") {
externalURLPublisher.send(url)
}
case .reportHistory:
break
Comment on lines +71 to +72
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사실 지금 크게 노메러이긴 하지만 .resetGoal과 케이스 합쳐두 될 것 같아유

Suggested change
case .reportHistory:
break
case .resetGoal, .reportHistory:
break

글구 // 임시 url 주석도 이젠 없어두 될 것 같숨당 ~~

}
}
}
37 changes: 37 additions & 0 deletions Projects/Presentation/Sources/Report/Model/ReportProgress+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// ReportProgress+.swift
// Presentation
//
// Created by 이동현 on 11/20/25.
//

import Domain
import UIKit

extension ReportProgress {
var backgroundColor: UIColor? {
switch self {
case .received:
BitnagilColor.green10
case .inProgress:
BitnagilColor.skyblue10
case .completed:
BitnagilColor.gray95
case .entire:
nil
}
}

var titleColor: UIColor? {
switch self {
case .received:
BitnagilColor.green500
case .inProgress:
BitnagilColor.blue300
case .completed:
BitnagilColor.gray40
case .entire:
nil
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// ReportProgressView.swift
// Presentation
//
// Created by 이동현 on 11/20/25.
//

import Domain
import SnapKit
import UIKit

final class ReportProgressView: UIView {

private enum Layout {
static let progressViewHeight: CGFloat = 26
static let progressLabelHeight: CGFloat = 18
static let progressLabelHorizontalSpacing: CGFloat = 10
static let progressLabelVerticalSpacing: CGFloat = 4
}

private let progressLabel = UILabel()

override init(frame: CGRect) {
super.init(frame: frame)
configureAttribute()
configureLayout()
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

private func configureAttribute() {
layer.cornerRadius = 6
layer.masksToBounds = true

progressLabel.font = BitnagilFont.init(style: .caption1, weight: .semiBold).font
}

private func configureLayout() {
addSubview(progressLabel)

self.snp.makeConstraints { make in
make.height.equalTo(Layout.progressViewHeight)
}

progressLabel.snp.makeConstraints { make in
make.height.equalTo(Layout.progressLabelHeight)

make.verticalEdges
.equalToSuperview()
.inset(Layout.progressLabelVerticalSpacing)

make.horizontalEdges
.equalToSuperview()
.inset(Layout.progressLabelHorizontalSpacing)
}
}
Comment on lines +40 to +58
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReportProgressView !!!!!!!! 나이쓰 따봉 ~~~

일케 하면 나중에 ReportProgressView 사용하는 곳에서 ReportProgressView의 레이아웃 사이즈 따로 안정해줘도 ReportProgress에 맞게 저절로 정해지나유 ??

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

일단은 그렇게 해두긴했는데, 호옥시 안되면 말씀해주세요!!


func configure(with progress: ReportProgress) {
backgroundColor = progress.backgroundColor

progressLabel.textColor = progress.titleColor
progressLabel.text = progress.description
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//
// ReportHistoryEmptyView.swift
// Presentation
//
// Created by 이동현 on 11/20/25.
//

import SnapKit
import UIKit

final class ReportHistoryEmptyView: UIView {
private enum Layout {
static let semiBoldLabelHeight: CGFloat = 28
static let regularLabelHeight: CGFloat = 20
static let stackViewSpacing: CGFloat = 2
static let stackViewHeight: CGFloat = 50
static let stackViewWidth: CGFloat = 269
}

private let labelStackView = UIStackView()
private let semiBoldLabel = UILabel()
private let regularLabel = UILabel()

override init(frame: CGRect) {
super.init(frame: frame)

configureAttribute()
configureLayout()
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

private func configureAttribute() {
backgroundColor = BitnagilColor.gray99

labelStackView.axis = .vertical
labelStackView.alignment = .center

semiBoldLabel.font = BitnagilFont.init(style: .subtitle1, weight: .semiBold).font
semiBoldLabel.textColor = BitnagilColor.gray30
semiBoldLabel.text = "제보한 내역이 없어요."

regularLabel.font = BitnagilFont.init(style: .body2, weight: .regular).font
regularLabel.textColor = BitnagilColor.gray70
regularLabel.text = "원하는 카테고리로 제보를 시작해보세요."
}

private func configureLayout() {
addSubview(labelStackView)
labelStackView.addArrangedSubview(semiBoldLabel)
labelStackView.addArrangedSubview(regularLabel)

labelStackView.snp.makeConstraints { make in
make.center.equalToSuperview()
make.height.equalTo(Layout.stackViewHeight)
make.width.equalTo(Layout.stackViewWidth)
}

semiBoldLabel.snp.makeConstraints { make in
make.height.equalTo(Layout.semiBoldLabelHeight)
}

regularLabel.snp.makeConstraints { make in
make.height.equalTo(Layout.regularLabelHeight)
}
}
}
Loading