Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
17 changes: 17 additions & 0 deletions MLS/MLS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
779A490E2E1AD26700ABDE4F /* BookmarkFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 779A490C2E1AD26700ABDE4F /* BookmarkFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
779A49102E1AD26D00ABDE4F /* BookmarkFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 779A490F2E1AD26D00ABDE4F /* BookmarkFeatureInterface.framework */; };
779A49112E1AD26D00ABDE4F /* BookmarkFeatureInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 779A490F2E1AD26D00ABDE4F /* BookmarkFeatureInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
77B1F9952EE06A4E00AE4B4D /* RxGesture in Frameworks */ = {isa = PBXBuildFile; productRef = 77B1F9942EE06A4E00AE4B4D /* RxGesture */; };
77EB18D62DED9256004FB380 /* AuthFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77EB18D52DED9256004FB380 /* AuthFeature.framework */; };
77EB18D72DED9256004FB380 /* AuthFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77EB18D52DED9256004FB380 /* AuthFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
Expand Down Expand Up @@ -166,6 +167,7 @@
08ED492C2DCFDED4002C21A2 /* RxSwift in Frameworks */,
7721A5042E0EE7AE00A7B58C /* BaseFeature.framework in Frameworks */,
08DA58AA2E1E5BEB009097A6 /* DictionaryFeatureInterface.framework in Frameworks */,
77B1F9952EE06A4E00AE4B4D /* RxGesture in Frameworks */,
7721A5082E0EE7F100A7B58C /* ReactorKit in Frameworks */,
0801759F2DCD27E600D0919F /* DomainInterface.framework in Frameworks */,
7777F7022E9EAB8400F53D68 /* BookmarkFeature.framework in Frameworks */,
Expand Down Expand Up @@ -323,6 +325,7 @@
08DA51B32E1B9827009097A6 /* FirebaseFirestore */,
08DA51B52E1B9827009097A6 /* FirebaseMessaging */,
770ADB1E2E433EDA00270506 /* RxKeyboard */,
77B1F9942EE06A4E00AE4B4D /* RxGesture */,
);
productName = MLS;
productReference = 087D3EE82DA7972C002F924D /* MLS.app */;
Expand Down Expand Up @@ -386,6 +389,7 @@
7721A5062E0EE7F100A7B58C /* XCRemoteSwiftPackageReference "ReactorKit" */,
08DA51B22E1B9827009097A6 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */,
770ADB1D2E433EDA00270506 /* XCRemoteSwiftPackageReference "RxKeyboard" */,
77B1F9932EE06A4E00AE4B4D /* XCRemoteSwiftPackageReference "RxGesture" */,
);
preferredProjectObjectVersion = 77;
productRefGroup = 087D3EE92DA7972C002F924D /* Products */;
Expand Down Expand Up @@ -810,6 +814,14 @@
kind = branch;
};
};
77B1F9932EE06A4E00AE4B4D /* XCRemoteSwiftPackageReference "RxGesture" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/RxSwiftCommunity/RxGesture.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 4.0.4;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
Expand Down Expand Up @@ -863,6 +875,11 @@
package = 77660AD32DD0D3DD007A4EF3 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */;
productName = KakaoSDKUser;
};
77B1F9942EE06A4E00AE4B4D /* RxGesture */ = {
isa = XCSwiftPackageProductDependency;
package = 77B1F9932EE06A4E00AE4B4D /* XCRemoteSwiftPackageReference "RxGesture" */;
productName = RxGesture;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 087D3EE02DA7972C002F924D /* Project object */;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ open class BaseListView: UIView {
static let iconSize: CGFloat = 24
static let stackViewSpacing: CGFloat = 12
static let topMargin: CGFloat = 12
static let nonFilterTopMargin: CGFloat = 20
static let cellSpacing: CGFloat = 10
static let cellWidth: CGFloat = 343
static let cellHeight: CGFloat = 104
Expand Down Expand Up @@ -80,8 +79,7 @@ private extension BaseListView {
func setupConstraints(isFilterHidden: Bool) {
if isFilterHidden {
listCollectionView.snp.makeConstraints { make in
make.top.equalToSuperview().inset(Constant.nonFilterTopMargin)
make.horizontalEdges.bottom.equalToSuperview()
make.edges.equalToSuperview()
}
} else {
filterStackView.snp.makeConstraints { make in
Expand Down Expand Up @@ -118,7 +116,7 @@ public extension BaseListView {
if hasFilter {
make.top.equalTo(filterStackView.snp.bottom).offset(Constant.topMargin)
} else {
make.top.equalToSuperview().inset(Constant.nonFilterTopMargin)
make.top.equalToSuperview()
}
make.horizontalEdges.bottom.equalToSuperview()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ public final class DictionaryListCell: UICollectionViewCell {

// MARK: - Components
public let cellView = CardList()
private var imageDownloadTask: URLSessionDataTask?

// MARK: - init
override init(frame: CGRect) {
Expand All @@ -23,6 +22,16 @@ public final class DictionaryListCell: UICollectionViewCell {
required init?(coder: NSCoder) {
fatalError("\(#file), \(#function) Error")
}

override public func prepareForReuse() {
super.prepareForReuse()

onBookmarkTapped = nil
cellView.onIconTapped = nil
cellView.setMainText(text: "")
cellView.setSubText(text: nil)
cellView.setSelected(isSelected: false)
}
}

// MARK: - SetUp
Expand Down Expand Up @@ -55,15 +64,32 @@ public extension DictionaryListCell {
}
}

func inject(type: CardList.CardListType, input: Input, onBookmarkTapped: @escaping (Bool) -> Void) {
func inject(
type: CardList.CardListType,
input: Input,
indexPath: IndexPath,
collectionView: UICollectionView,
isMap: Bool = false,
onBookmarkTapped: @escaping (Bool) -> Void
) {
cellView.setType(type: type)
// URL이 유효할 때만 요청
cellView.setImage(image: UIImage(), backgroundColor: input.type.backgroundColor) // 초기화

if let url = URL(string: input.imageUrl) {
ImageLoader.shared.loadImage(url: url) { image in
guard let image = image else { return }
self.cellView.setImage(image: image, backgroundColor: input.type.backgroundColor)
ImageLoader.shared.loadImage(url: url) { [weak self] image in
guard let self = self else { return }
// ⚠️ 셀이 재사용된 경우, indexPath가 다르면 무시
if let currentIndex = collectionView.indexPath(for: self),
currentIndex == indexPath {
if isMap {
self.cellView.setMapImage(image: image ?? UIImage(), backgroundColor: input.type.backgroundColor)
} else {
self.cellView.setImage(image: image ?? UIImage(), backgroundColor: input.type.backgroundColor)
}
}
}
}

cellView.setMainText(text: input.mainText)
cellView.setSubText(text: input.subText)
cellView.setSelected(isSelected: input.isBookmarked)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ public class LayoutFactory {
.contentInsets(.init(top: 12, leading: 16, bottom: 32, trailing: 16))
}

public func getDictionaryListLayout() -> CompositionalSectionBuilder {
public func getDictionaryListLayout(isFilterHidden: Bool = true) -> CompositionalSectionBuilder {
return CompositionalSectionBuilder()
.item(width: .fractionalWidth(1.0), height: .absolute(104))
.group(.horizontal, width: .fractionalWidth(1.0), height: .absolute(104))
.buildSection()
.interGroupSpacing(10)
.contentInsets(.init(top: 0, leading: 16, bottom: 0, trailing: 16))
.contentInsets(.init(top: isFilterHidden ? 20 : 0, leading: 16, bottom: 0, trailing: 16))
}

public func getTagChipLayout() -> CompositionalSectionBuilder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,10 @@ private extension BookmarkListViewController {
}

func createListLayout() -> UICollectionViewLayout {
guard let isHidden = reactor?.currentState.type.isBookmarkSortHidden else { return UICollectionViewLayout() }
let layoutFactory = LayoutFactory()
let layout = CompositionalLayoutBuilder()
.section { _ in layoutFactory.getDictionaryListLayout() }
.section { _ in layoutFactory.getDictionaryListLayout(isFilterHidden: isHidden) }
.build()
layout.register(Neutral300DividerView.self, forDecorationViewOfKind: Neutral300DividerView.identifier)
return layout
Expand Down Expand Up @@ -248,6 +249,9 @@ extension BookmarkListViewController: UICollectionViewDelegate, UICollectionView
imageUrl: item.imageUrl ?? "",
isBookmarked: true
),
indexPath: indexPath,
collectionView: collectionView,
isMap: item.type == .map,
onBookmarkTapped: { [weak self] isSelected in
guard let self = self else { return }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ extension CollectionDetailViewController: UICollectionViewDelegate, UICollection
imageUrl: item.imageUrl ?? "",
isBookmarked: true
),
indexPath: indexPath,
collectionView: collectionView,
onBookmarkTapped: { [weak self] isSelected in
guard let self = self else { return }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,16 @@ extension CollectionEditViewController: UICollectionViewDelegate, UICollectionVi
}

cell.inject(
type: .checkbox,
type: .bookmark,
input: DictionaryListCell.Input(
type: item.type,
mainText: item.name,
subText: subText,
imageUrl: item.imageUrl ?? "",
isBookmarked: isSelected
),
indexPath: indexPath,
collectionView: collectionView,
onBookmarkTapped: { [weak self] _ in
self?.reactor?.action.onNext(.itemTapped(indexPath.row))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public final class CardList: UIView {
var icon: UIImage? {
switch self {
case .bookmark:
return .bookmarkBorder
return .bookmarkBorderList
case .checkbox:
return .checkSquare
case .detailStack, .detailStackText, .detailStackBadge:
Expand All @@ -25,7 +25,7 @@ public final class CardList: UIView {
var selectedIcon: UIImage? {
switch self {
case .bookmark:
return .bookmark
return .bookmarkList
case .checkbox:
return .checkSquareFill
case .detailStack, .detailStackText, .detailStackBadge:
Expand All @@ -44,6 +44,7 @@ public final class CardList: UIView {
static let imageContentViewSize: CGFloat = 80
static let stackViewSpacing: CGFloat = 4
static let iconSize: CGFloat = 24
static let mapImageSize: CGFloat = 40
}

// MARK: - Properties
Expand Down Expand Up @@ -72,7 +73,7 @@ public final class CardList: UIView {
public var onIconTapped: ((Bool) -> Void)?

// MARK: - Components
private let imageView = ItemImageView(image: nil, cornerRadius: Constant.imageRadius, inset: Constant.imageInset, backgroundColor: .listMap)
public let imageView = ItemImageView(image: nil, cornerRadius: Constant.imageRadius, inset: Constant.imageInset, backgroundColor: .listMap)

Choose a reason for hiding this comment

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

medium

imageView의 접근 제어 수준을 public으로 변경하셨는데, 캡슐화를 위해 private으로 유지하는 것이 좋습니다. imageView의 속성을 외부에서 직접 변경하기보다는, CardList에 필요한 기능을 수행하는 메서드를 추가하여 노출하는 방식(예: setMapImage)을 사용하는 것이 더 안전하고 유지보수하기 좋은 코드 구조입니다. 외부에서 imageView에 직접 접근해야 하는 특별한 이유가 없다면 private으로 되돌리는 것을 고려해 보세요.

Suggested change
public let imageView = ItemImageView(image: nil, cornerRadius: Constant.imageRadius, inset: Constant.imageInset, backgroundColor: .listMap)
private let imageView = ItemImageView(image: nil, cornerRadius: Constant.imageRadius, inset: Constant.imageInset, backgroundColor: .listMap)


private lazy var textLabelStackView: UIStackView = {
let view = UIStackView(arrangedSubviews: [mainTextLabel, subTextLabel])
Expand Down Expand Up @@ -119,7 +120,6 @@ public final class CardList: UIView {
let stack = UIStackView(arrangedSubviews: [dropTitleLabel, dropValueLabel])
stack.axis = .vertical
stack.alignment = .trailing
stack.spacing = 2
stack.isHidden = true // 기본은 숨김
return stack
}()
Expand Down Expand Up @@ -158,24 +158,30 @@ private extension CardList {

textLabelStackView.snp.makeConstraints { make in
make.leading.equalTo(imageView.snp.trailing).offset(Constant.cardLeadingInset)
make.trailing.lessThanOrEqualTo(dropInfoStack.snp.leading).offset(-Constant.cardLeadingInset)
make.centerY.equalToSuperview()
make.trailing.lessThanOrEqualToSuperview().inset(Constant.cardTrailingInset)
}

iconButton.snp.makeConstraints { make in
dropInfoStack.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.trailing.equalToSuperview().inset(Constant.cardTrailingInset)
make.size.equalTo(Constant.iconSize)
}

badge.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.trailing.equalToSuperview().inset(Constant.cardTrailingInset)
}

dropInfoStack.snp.makeConstraints { make in
iconButton.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.trailing.equalToSuperview().inset(Constant.cardTrailingInset)
make.size.equalTo(Constant.iconSize)
}

textLabelStackView.snp.makeConstraints { make in
make.trailing.lessThanOrEqualTo(dropInfoStack.snp.leading).offset(-Constant.cardLeadingInset)
make.trailing.lessThanOrEqualTo(badge.snp.leading).offset(-Constant.cardLeadingInset)
make.trailing.lessThanOrEqualTo(iconButton.snp.leading).offset(-Constant.cardLeadingInset)
}
}

Expand Down Expand Up @@ -210,15 +216,17 @@ public extension CardList {
}

func setSubText(text: String?) {
if let text = text {
subText = text
}
subText = text
}

func setImage(image: UIImage, backgroundColor: UIColor) {
imageView.setImage(image: image, backgroundColor: backgroundColor)
}

func setMapImage(image: UIImage, backgroundColor: UIColor) {
imageView.setMapImage(image: image, backgroundColor: backgroundColor)
}

func setSelected(isSelected: Bool) {
isIconSelected = isSelected
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,12 @@ public extension ItemImageView {
imageView.image = image
self.backgroundColor = backgroundColor
}

func setMapImage(image: UIImage?, backgroundColor: UIColor) {
setImage(image: image, backgroundColor: backgroundColor)
imageView.snp.remakeConstraints { make in
make.center.equalToSuperview()
make.size.equalTo(40)

Choose a reason for hiding this comment

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

medium

setMapImage 메서드 내에서 이미지 크기를 40으로 고정하고 있습니다. 이 값을 '매직 넘버'로 사용하기보다는, 의미를 명확히 하고 재사용성을 높이기 위해 상수로 정의하는 것이 좋습니다. 예를 들어, ItemImageView 내에 private enum Constant { static let mapImageSize: CGFloat = 40 }와 같이 상수를 선언하고 make.size.equalTo(Constant.mapImageSize)와 같이 사용하는 것을 고려해 보세요.

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@ import UIKit

import SnapKit

public protocol SearchBarDelegate: AnyObject {
func searchBarDidReturn(_ searchBar: SearchBar, text: String)
}

public final class SearchBar: UIView {
// MARK: - Properties
public weak var searchDelegate: SearchBarDelegate?

// MARK: - Components
public let backButton: UIButton = {
let button = UIButton(type: .system)
let image = DesignSystemAsset.image(named: "arrowBack")?.withRenderingMode(.alwaysTemplate)
Expand Down Expand Up @@ -139,6 +146,8 @@ extension SearchBar: UITextFieldDelegate {
}

public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
searchDelegate?.searchBarDidReturn(self, text: textField.text ?? "")

endEditing(true)
clearButton.isHidden = true
return true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"images" : [
{
"filename" : "bookmark_true.svg",
"filename" : "bookmark.svg",
"idiom" : "universal",
"scale" : "1x"
},
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "bookmark_border.svg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"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.
Loading