Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#6] 영화,드라마 선택 화면 구현 #13

Merged
merged 6 commits into from
Jan 26, 2025
Merged
Show file tree
Hide file tree
Changes from 5 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
44 changes: 44 additions & 0 deletions TodayVideo/TodayVideo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@
47B663CC8D8E3B9C6597D6A8 /* Pods_TodayVideo_TodayVideoUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFB8528AC96E0E4545364CA7 /* Pods_TodayVideo_TodayVideoUITests.framework */; };
642F696B881908AADE34D680 /* Pods_TodayVideoTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A000755573841D92675025D /* Pods_TodayVideoTests.framework */; };
CE0F3FF32D374BA40058CEAE /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0F3FF22D374BA40058CEAE /* UIColor+Extensions.swift */; };
CE0F3FF62D37714B0058CEAE /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0F3FF52D37714B0058CEAE /* ContentView.swift */; };
CE0F3FF82D3771C80058CEAE /* ContentPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0F3FF72D3771C80058CEAE /* ContentPresenter.swift */; };
CE0F3FFA2D3771D40058CEAE /* ContentRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0F3FF92D3771D40058CEAE /* ContentRouter.swift */; };
CE0F3FFE2D38A2850058CEAE /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0F3FFD2D38A2850058CEAE /* UIImage+Extension.swift */; };
CE0F40012D38A6590058CEAE /* FilterButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0F40002D38A6590058CEAE /* FilterButton.swift */; };
CE0F40032D38E0720058CEAE /* NextButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0F40022D38E0720058CEAE /* NextButton.swift */; };
CE0F40052D39D2B80058CEAE /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0F40042D39D2B80058CEAE /* String+Extension.swift */; };
CE9EAC182D2239E100971DB4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9EAC172D2239E100971DB4 /* AppDelegate.swift */; };
CE9EAC1A2D2239E100971DB4 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9EAC192D2239E100971DB4 /* SceneDelegate.swift */; };
CE9EAC1C2D2239E100971DB4 /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9EAC1B2D2239E100971DB4 /* SplashView.swift */; };
Expand Down Expand Up @@ -51,6 +58,13 @@
BDE0F86382A97508FF432E23 /* Pods-TodayVideo-TodayVideoUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TodayVideo-TodayVideoUITests.debug.xcconfig"; path = "Target Support Files/Pods-TodayVideo-TodayVideoUITests/Pods-TodayVideo-TodayVideoUITests.debug.xcconfig"; sourceTree = "<group>"; };
C7E44DA69C861B3423EEE105 /* Pods-TodayVideo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TodayVideo.debug.xcconfig"; path = "Target Support Files/Pods-TodayVideo/Pods-TodayVideo.debug.xcconfig"; sourceTree = "<group>"; };
CE0F3FF22D374BA40058CEAE /* UIColor+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extensions.swift"; sourceTree = "<group>"; };
CE0F3FF52D37714B0058CEAE /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
CE0F3FF72D3771C80058CEAE /* ContentPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentPresenter.swift; sourceTree = "<group>"; };
CE0F3FF92D3771D40058CEAE /* ContentRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentRouter.swift; sourceTree = "<group>"; };
CE0F3FFD2D38A2850058CEAE /* UIImage+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Extension.swift"; sourceTree = "<group>"; };
CE0F40002D38A6590058CEAE /* FilterButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterButton.swift; sourceTree = "<group>"; };
CE0F40022D38E0720058CEAE /* NextButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextButton.swift; sourceTree = "<group>"; };
CE0F40042D39D2B80058CEAE /* String+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = "<group>"; };
CE9EAC142D2239E100971DB4 /* TodayVideo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TodayVideo.app; sourceTree = BUILT_PRODUCTS_DIR; };
CE9EAC172D2239E100971DB4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
CE9EAC192D2239E100971DB4 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -111,10 +125,31 @@
isa = PBXGroup;
children = (
CE0F3FF22D374BA40058CEAE /* UIColor+Extensions.swift */,
CE0F3FFD2D38A2850058CEAE /* UIImage+Extension.swift */,
CE0F40042D39D2B80058CEAE /* String+Extension.swift */,
);
path = Extension;
sourceTree = "<group>";
};
CE0F3FF42D3771220058CEAE /* ContentView */ = {
isa = PBXGroup;
children = (
CE0F3FF52D37714B0058CEAE /* ContentView.swift */,
CE0F3FF72D3771C80058CEAE /* ContentPresenter.swift */,
CE0F3FF92D3771D40058CEAE /* ContentRouter.swift */,
);
path = ContentView;
sourceTree = "<group>";
};
CE0F3FFF2D38A63F0058CEAE /* Common */ = {
isa = PBXGroup;
children = (
CE0F40002D38A6590058CEAE /* FilterButton.swift */,
CE0F40022D38E0720058CEAE /* NextButton.swift */,
);
path = Common;
sourceTree = "<group>";
};
CE9EAC0B2D2239E100971DB4 = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -146,8 +181,10 @@
CE9EAC202D2239E200971DB4 /* Assets.xcassets */,
CE9EAC222D2239E200971DB4 /* LaunchScreen.storyboard */,
CE9EAC252D2239E200971DB4 /* Info.plist */,
CE0F3FFF2D38A63F0058CEAE /* Common */,
CE0F3FF12D374B0F0058CEAE /* Extension */,
CE9EAC472D223ACC00971DB4 /* SplashView */,
CE0F3FF42D3771220058CEAE /* ContentView */,
);
path = TodayVideo;
sourceTree = "<group>";
Expand Down Expand Up @@ -433,10 +470,17 @@
files = (
CE9EAC1C2D2239E100971DB4 /* SplashView.swift in Sources */,
CE0F3FF32D374BA40058CEAE /* UIColor+Extensions.swift in Sources */,
CE0F3FF62D37714B0058CEAE /* ContentView.swift in Sources */,
CE9EAC182D2239E100971DB4 /* AppDelegate.swift in Sources */,
CE0F3FF82D3771C80058CEAE /* ContentPresenter.swift in Sources */,
CE9EAC4B2D223B2D00971DB4 /* SplashRouter.swift in Sources */,
CE0F40032D38E0720058CEAE /* NextButton.swift in Sources */,
CE0F40012D38A6590058CEAE /* FilterButton.swift in Sources */,
CE9EAC492D223B2300971DB4 /* SplashPresenter.swift in Sources */,
CE0F3FFE2D38A2850058CEAE /* UIImage+Extension.swift in Sources */,
CE0F40052D39D2B80058CEAE /* String+Extension.swift in Sources */,
CE9EAC1A2D2239E100971DB4 /* SceneDelegate.swift in Sources */,
CE0F3FFA2D3771D40058CEAE /* ContentRouter.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
12 changes: 12 additions & 0 deletions TodayVideo/TodayVideo/Assets.xcassets/next.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Vector.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 41 additions & 0 deletions TodayVideo/TodayVideo/Common/FilterButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// FilterButton.swift
// TodayVideo
//
// Created by iOS Dev on 1/16/25.
//

import UIKit

class FilterButton: UIButton {

Choose a reason for hiding this comment

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

FilterButton 클래스를 추후 확장하거나 상속시킬 계획이 없다면 final 키워드를 추가해서 파이널 클래스로 정의해주는 것이 좋습니다.

숙제) 그 이유에 대해서 찾아보시고, 다음 멘토링 때 이야기 나누도록 하시죠 :)

let height = 50.0
var title = ""

init(title: String) {
super.init(frame: .zero)

self.title = title
self.setTitle(title, for: .normal)
self.layer.cornerRadius = height / 2
}

required init?(coder: NSCoder) {
super.init(coder: coder)
}

func width() -> CGFloat {
let titleWidth = title.width(size: 20)
let leftRightMargin = 70.0

Choose a reason for hiding this comment

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

Suggested change
let leftRightMargin = 70.0
let leftRightMargin: CGFloat = 70.0

Choose a reason for hiding this comment

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

70.0과 같은 매직 넘버는 상수로 바꾸어 가독성을 높일 수 있습니다. 예를 들어, leftRightMargin 값을 상수로 정의하고 재사용할 수 있습니다.

Suggested change
let leftRightMargin = 70.0
private let leftRightMargin: CGFloat = 70.0

return titleWidth + leftRightMargin
}

func updateState() {
if isSelected {
self.setTitleColor(.buttonSelectedText, for: .normal)
self.backgroundColor = .buttonSelectedBackground
} else {
self.setTitleColor(.buttonDefaultText, for: .normal)
self.backgroundColor = .buttonDefaultBackground
}

Choose a reason for hiding this comment

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

  1. isSelected에 따라 UI 상태를 변경하는 부분은 좋은 방식입니다. 그러나, 이 함수에서 UI 업데이트 시 중복된 코드가 발생하고 있습니다. setTitleColorbackgroundColor에 대해 같은 조건에 맞는 중복 코드가 두 번 작성되어 있습니다. 이를 함수화하거나 별도의 메서드를 만들어 중복을 줄이는 것이 좋습니다.
  2. 굳이 필요하지 않다면, self를 사용할 필요가 없습니다. self는 메서드나 프로퍼티의 이름과 충돌할 가능성이 있을 때만 사용하는 것이 좋습니다. 이 경우 self 없이도 정상적으로 코드가 작동합니다.

}
}
45 changes: 45 additions & 0 deletions TodayVideo/TodayVideo/Common/NextButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// NextButton.swift
// TodayVideo
//
// Created by iOS Dev on 1/16/25.
//

import UIKit
import SnapKit

class NextButton: UIButton {
var currentView: UIViewController!

init(location: UIViewController) {
super.init(frame: .zero)

self.currentView = location
self.setImage(.nextButton, for: .normal)
self.addTarget(self, action: #selector(pushToNextView), for: .touchUpInside)
self.currentView.view.addSubview(self)
self.layout(in: currentView.view)
}

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

func layout(in view: UIView) {
self.snp.makeConstraints { make in
make.width.equalTo(15.4)
make.height.equalTo(23)
make.trailing.equalTo(view.snp.trailing).offset(-41.6)
make.bottom.equalTo(view.snp.bottom).offset(-78)
}
}

@objc private func pushToNextView() {
switch currentView {
case is ContentView:
guard let contentView = currentView as? ContentView else { return }
contentView.presenter?.pushToGenreView()
default: break
}
}
}
22 changes: 22 additions & 0 deletions TodayVideo/TodayVideo/ContentView/ContentPresenter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// ContentPresenter.swift
// TodayVideo
//
// Created by iOS Dev on 1/15/25.
//

import Foundation

protocol ContentPresenterProtocol {
func pushToGenreView()
}

final class ContentPresenter: ContentPresenterProtocol {
var router: ContentRouterProtocol?

func pushToGenreView() {
DispatchQueue.main.async {
self.router?.pushToGenreView()
}
}
}
34 changes: 34 additions & 0 deletions TodayVideo/TodayVideo/ContentView/ContentRouter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// ContentRouter.swift
// TodayVideo
//
// Created by iOS Dev on 1/15/25.
//

import UIKit

protocol ContentRouterProtocol {
func pushToGenreView()
}

final class ContentRouter: ContentRouterProtocol {
weak var contentView: ContentView?

static func createContentViewModule() -> ContentView {
let view = ContentView()
let presenter = ContentPresenter()
let router = ContentRouter()

view.presenter = presenter
presenter.router = router
router.contentView = view

return view
}

// 장르 선택 화면으로 push
func pushToGenreView() {
// let genreView = GenreRouter.createGenre
// contentView?.navigationController?.pushViewController(genreView, animated: true)
Comment on lines +32 to +33

Choose a reason for hiding this comment

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

PR 올리실 때에는 임의 주석 처리한 코드는 정리해주시는 것이 좋습니다.

}
}
92 changes: 92 additions & 0 deletions TodayVideo/TodayVideo/ContentView/ContentView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//
// ContentView.swift
// TodayVideo
//
// Created by iOS Dev on 1/15/25.
//

import UIKit
import SnapKit

class ContentView: UIViewController {
var presenter: ContentPresenterProtocol?

private var movieButton: FilterButton!
private var tvButton: FilterButton!
private let movie = "영화"
private let tv = "TV"
private lazy var selectedContent = movie

Choose a reason for hiding this comment

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

selectedContent는 선택된 컨텐츠를 저장하는데 사용되지만, movieButtontvButton의 상태 변경에 따라 selectedContent가 변경되는 구조로 판단됩니다. 만약 나중에 선택된 콘텐츠에 따라 다른 처리가 필요하다면, selectedContentenum 타입으로 변경하기를 권장드립니다.


override func viewDidLoad() {
super.viewDidLoad()

drawUI()
buttonSelected(movieButton)
}

private func drawUI() {
self.view.backgroundColor = .background

// 영화, 드라마 버튼
/// 컨테이너
let height = 50.0
let containerView = UIView()
let containerViewWidth = 300.0

self.view.addSubview(containerView)

containerView.snp.makeConstraints { make in
make.center.equalToSuperview()
make.height.equalTo(height)
make.width.equalTo(containerViewWidth)
}

/// 버튼
movieButton = FilterButton(title: movie)
tvButton = FilterButton(title: tv)

[movieButton, tvButton].forEach { button in
button.addTarget(self, action: #selector(buttonSelected(_:)), for: .touchUpInside)
containerView.addSubview(button)
}

let margin = 8.0
let buttonWidth = (containerViewWidth / 2) - margin

movieButton.snp.makeConstraints { make in
make.left.top.bottom.equalToSuperview()
make.width.equalTo(buttonWidth)
}

tvButton.snp.makeConstraints { make in
make.right.top.bottom.equalToSuperview()
make.width.equalTo(buttonWidth)
}

// 다음 버튼
let _ = NextButton(location: self)

Choose a reason for hiding this comment

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

이 부분이 잘 이해가지 않네요. 할당하지 않는데 왜 생성되었을까요?

}

@objc private func buttonSelected(_ sender: UIButton) {
// 이미 선택되어 있는 버튼이면 return
if sender.isSelected {
return
}

sender.isSelected = !sender.isSelected

DispatchQueue.main.async {
if sender == self.movieButton {
self.selectedContent = self.movie
self.tvButton.isSelected = false
self.tvButton.updateState()
self.movieButton.updateState()
} else {
self.selectedContent = self.tv
self.movieButton.isSelected = false
self.movieButton.updateState()
self.tvButton.updateState()
}
}
}
}
16 changes: 16 additions & 0 deletions TodayVideo/TodayVideo/Extension/String+Extension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// String+Extension.swift
// TodayVideo
//
// Created by iOS Dev on 1/17/25.
//

import UIKit

extension String {
func width(size: CGFloat) -> CGFloat {
let font = UIFont.systemFont(ofSize: size)
let attributes: [NSAttributedString.Key: Any] = [.font: font]
return self.size(withAttributes: attributes).width
}
}
5 changes: 5 additions & 0 deletions TodayVideo/TodayVideo/Extension/UIColor+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ extension UIColor {
static let title1 = UIColor(hex: "#4AFFF3") ?? .red
static let title2 = UIColor(hex: "#264CA5") ?? .red
static let title3 = UIColor(hex: "#000000") ?? .black
// ContentView
static let buttonDefaultBackground = UIColor(hex: "#1E2122") ?? .gray
static let buttonDefaultText = UIColor(hex: "#FDFDFD") ?? .white
static let buttonSelectedBackground = UIColor(hex: "#3B84A8") ?? .blue
static let buttonSelectedText = UIColor(hex: "#1E2122") ?? .black
}

extension UIColor {
Expand Down
12 changes: 12 additions & 0 deletions TodayVideo/TodayVideo/Extension/UIImage+Extension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// UIImage+Extension.swift
// TodayVideo
//
// Created by iOS Dev on 1/16/25.
//

import UIKit

extension UIImage {
static let nextButton = UIImage(named: "next")
}
Loading
Loading