From be0ab8ca651090e644790d532b8a19431f9f0521 Mon Sep 17 00:00:00 2001 From: p2glet Date: Tue, 24 Feb 2026 18:11:37 +0900 Subject: [PATCH 1/3] =?UTF-8?q?fix/#280:=20=EC=95=8C=EB=A6=BC=20=EC=9D=BD?= =?UTF-8?q?=EC=9D=8C=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?/=20=EC=B5=9C=EA=B7=BC=20=EA=B2=80=EC=83=89=EC=96=B4=20?= =?UTF-8?q?=EB=AA=A8=EB=91=90=20=EC=A7=80=EC=9A=B0=EA=B8=B0=20=ED=81=B4?= =?UTF-8?q?=EB=A6=AD=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?/=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=83=81=ED=83=9C=EC=97=90?= =?UTF-8?q?=20=EB=94=B0=EB=A5=B8=20=EB=B6=81=EB=A7=88=ED=81=AC=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Endpoints/DictionaryListEndPoint.swift | 2 +- .../Repository/UserDefaultsRepositoryImpl.swift | 15 +++++++++++++++ .../RecentSearchRemoveUseCaseImpl.swift | 5 +++++ .../Repository/UserDefaultsRepository.swift | 1 + .../RecentSearch/RecentSearchRemoveUseCase.swift | 1 + .../DictionaryNotificationCell.swift | 2 +- .../Views/RecentSearchHeaderView.swift | 2 +- .../BookmarkList/BookmarkListViewController.swift | 2 +- .../DictionaryListViewController.swift | 3 ++- .../DictionarySearchReactor.swift | 7 +++++++ .../DictionarySearchViewController.swift | 12 ++++++++++-- 11 files changed, 45 insertions(+), 7 deletions(-) diff --git a/MLS/Data/Data/Network/Endpoints/DictionaryListEndPoint.swift b/MLS/Data/Data/Network/Endpoints/DictionaryListEndPoint.swift index 1f31fedb..9de13a79 100644 --- a/MLS/Data/Data/Network/Endpoints/DictionaryListEndPoint.swift +++ b/MLS/Data/Data/Network/Endpoints/DictionaryListEndPoint.swift @@ -47,7 +47,7 @@ public enum DictionaryListEndPoint { let joinedCategoryIds = categoryIds?.map(String.init).joined(separator: ",") let joinedJobIds = jobId?.map(String.init).joined(separator: ",") - let query = DictionaryListQuery(keyword: keyword, page: page ?? 0, size: size ?? 20, sort: sort, minLevel: minLevel ?? 1, maxLevel: maxLevel ?? 200, jobIds: joinedJobIds, categoryIds: joinedCategoryIds) + let query = DictionaryListQuery(keyword: keyword, page: page ?? 0, size: size ?? 20, sort: sort, minLevel: minLevel, maxLevel: maxLevel, jobIds: joinedJobIds, categoryIds: joinedCategoryIds) return .init(baseURL: base, path: "/api/v1/items", method: .GET, query: query ) } diff --git a/MLS/Data/Data/Repository/UserDefaultsRepositoryImpl.swift b/MLS/Data/Data/Repository/UserDefaultsRepositoryImpl.swift index 991699f3..e665e03f 100644 --- a/MLS/Data/Data/Repository/UserDefaultsRepositoryImpl.swift +++ b/MLS/Data/Data/Repository/UserDefaultsRepositoryImpl.swift @@ -49,6 +49,21 @@ public final class UserDefaultsRepositoryImpl: UserDefaultsRepository { return Disposables.create() } } + + public func removeAllSearch() -> Completable { + return Completable.create { completable in + var current = UserDefaults.standard.stringArray(forKey: self.recentSearchkey) ?? [] + + // 해당 키워드 제거 + current.removeAll() + + // 다시 저장 + UserDefaults.standard.set(current, forKey: self.recentSearchkey) + + completable(.completed) + return Disposables.create() + } + } public func fetchPlatform() -> Observable { return Observable.create { observer in diff --git a/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchRemoveUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchRemoveUseCaseImpl.swift index 9fdb545c..d6959984 100644 --- a/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchRemoveUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchRemoveUseCaseImpl.swift @@ -5,6 +5,7 @@ import RxSwift public class RecentSearchRemoveUseCaseImpl: RecentSearchRemoveUseCase { var repository: UserDefaultsRepository + public init(repository: UserDefaultsRepository) { self.repository = repository } @@ -12,4 +13,8 @@ public class RecentSearchRemoveUseCaseImpl: RecentSearchRemoveUseCase { public func remove(keyword: String) -> Completable { return repository.removeRecentSearch(keyword: keyword) } + + public func removeAll() -> Completable { + return repository.removeAllSearch() + } } diff --git a/MLS/Domain/DomainInterface/Repository/UserDefaultsRepository.swift b/MLS/Domain/DomainInterface/Repository/UserDefaultsRepository.swift index 763c10d2..f837248e 100644 --- a/MLS/Domain/DomainInterface/Repository/UserDefaultsRepository.swift +++ b/MLS/Domain/DomainInterface/Repository/UserDefaultsRepository.swift @@ -4,6 +4,7 @@ public protocol UserDefaultsRepository { func fetchRecentSearch() -> Observable<[String]> func addRecentSearch(keyword: String) -> Completable func removeRecentSearch(keyword: String) -> Completable + func removeAllSearch() -> Completable func fetchPlatform() -> Observable func savePlatform(platform: LoginPlatform) -> Completable diff --git a/MLS/Domain/DomainInterface/UseCase/RecentSearch/RecentSearchRemoveUseCase.swift b/MLS/Domain/DomainInterface/UseCase/RecentSearch/RecentSearchRemoveUseCase.swift index 19a89a8f..5a6e9792 100644 --- a/MLS/Domain/DomainInterface/UseCase/RecentSearch/RecentSearchRemoveUseCase.swift +++ b/MLS/Domain/DomainInterface/UseCase/RecentSearch/RecentSearchRemoveUseCase.swift @@ -2,4 +2,5 @@ import RxSwift public protocol RecentSearchRemoveUseCase { func remove(keyword: String) -> Completable + func removeAll() -> Completable } diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/DictionaryNotificationCell.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/DictionaryNotificationCell.swift index 478d83d0..db03aa1d 100644 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/DictionaryNotificationCell.swift +++ b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/DictionaryNotificationCell.swift @@ -84,6 +84,6 @@ public extension DictionaryNotificationCell { subTitleLabel.attributedText = .makeStyledString(font: .b_s_r, text: input.subTitle, color: input.isChecked ? .neutral500 : .neutral700, alignment: .left) backgroundColor = input.isChecked ? .neutral100 : .clearMLS layer.cornerRadius = input.isChecked ? Constant.radius : 0 - checkIcon.isHidden = !input.isChecked + checkIcon.isHidden = input.isChecked } } diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/RecentSearchHeaderView.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/RecentSearchHeaderView.swift index cfb1606a..878213a8 100644 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/RecentSearchHeaderView.swift +++ b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/RecentSearchHeaderView.swift @@ -5,7 +5,7 @@ import UIKit public final class RecentSearchHeaderView: UICollectionReusableView { // MARK: - Components private let titleLabel = UILabel() - private let deleteButton = UIButton() + public let deleteButton = UIButton() private let spacer = UIView() // MARK: - Init diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift index 5f7e9777..853d175a 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift @@ -339,7 +339,7 @@ extension BookmarkListViewController: UICollectionViewDelegate, UICollectionView onBookmarkTapped: { [weak self] in guard let self else { return } - guard state.isLogin else { + guard self.reactor?.currentState.isLogin == true else { self.reactor?.action.onNext(.showLogin) return } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift index 6f22ceef..15b60e0b 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift @@ -372,7 +372,7 @@ extension DictionaryListViewController: UICollectionViewDelegate, UICollectionVi isMap: item.type == .map, onBookmarkTapped: { [weak self] in guard let self else { return } - guard state.isLogin else { + guard self.reactor?.currentState.isLogin == true else { self.reactor?.action.onNext(.showLogin) return } @@ -418,3 +418,4 @@ extension DictionaryListViewController: UICollectionViewDelegate, UICollectionVi } } } + diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchReactor.swift index cb2819dd..98e3b950 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchReactor.swift @@ -20,12 +20,14 @@ public final class DictionarySearchReactor: Reactor { case backButtonTapped case searchButtonTapped(String) case cancelRecentButtonTapped(String) + case deleteAllButtonTapped case recentButtonTapped(String) } public enum Mutation { case navigateTo(Route) case deleteItem(String) + case deleteAllItems case addRecentItem(String) case setRecentList([String]) } @@ -106,6 +108,9 @@ public final class DictionarySearchReactor: Reactor { .andThen(.just(.deleteItem(keyword))) case .recentButtonTapped(let keyword): return Observable.just(.navigateTo(.search(keyword))) + case .deleteAllButtonTapped: + return recentSearchRemoveUseCase.removeAll() + .andThen(.just(.deleteAllItems)) } } @@ -121,6 +126,8 @@ public final class DictionarySearchReactor: Reactor { newState.recentResult.insert(name, at: 0) // 맨 앞에 최근 검색어 추가 case .deleteItem(let name): newState.recentResult = state.recentResult.filter { $0 != name } + case .deleteAllItems: + newState.recentResult = [] } return newState diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift index a1b2dede..75acf602 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift @@ -242,11 +242,19 @@ extension DictionarySearchViewController: UICollectionViewDelegate, UICollection ) -> UICollectionReusableView { switch indexPath.section { case 0: - let view = collectionView.dequeueReusableSupplementaryView( + guard let view = collectionView.dequeueReusableSupplementaryView( ofKind: kind, withReuseIdentifier: RecentSearchHeaderView.identifier, for: indexPath - ) as! RecentSearchHeaderView + ) as? RecentSearchHeaderView else { return UICollectionViewCell() } + + guard let reactor = reactor else { return UICollectionViewCell() } + + view.deleteButton.rx.tap + .map { Reactor.Action.deleteAllButtonTapped } + .bind(to: reactor.action) + .disposed(by: disposeBag) + return view case 2: From 2c29a9148b11a30d15f44200614622fa27c310f5 Mon Sep 17 00:00:00 2001 From: p2glet Date: Tue, 24 Feb 2026 23:41:01 +0900 Subject: [PATCH 2/3] =?UTF-8?q?fix/#280:=20=EC=83=81=EC=84=B8=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20=EC=A0=84=ED=99=98=20=EC=8B=9C=20UI=20=EA=B0=B1?= =?UTF-8?q?=EC=8B=A0=20=ED=83=80=EC=9D=B4=EB=B0=8D=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DictionaryDetailBaseViewController.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift index 4245a583..84d5dfcb 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift @@ -22,9 +22,9 @@ class DictionaryDetailBaseViewController: BaseViewController { /// 각 탭에 해당하는 콘텐츠 뷰들을 담는 배열 public var contentViews: [UIView] = [] { didSet { - if let index = currentTabIndex { - mainView.setTabView(index: index, contentViews: contentViews) - } + let index = currentTabIndex ?? 0 + guard index < contentViews.count else { return } + mainView.setTabView(index: index, contentViews: contentViews) } } From 7f0f10a26ec38048ec4b3e6e0fdc030aeb0bf456 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 24 Feb 2026 14:44:22 +0000 Subject: [PATCH 3/3] style/#280: Apply SwiftLint autocorrect --- MLS/Data/Data/Repository/UserDefaultsRepositoryImpl.swift | 2 +- .../RecentSearch/RecentSearchRemoveUseCaseImpl.swift | 4 ++-- .../DictionaryList/DictionaryListViewController.swift | 1 - .../DictionarySearch/DictionarySearchViewController.swift | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/MLS/Data/Data/Repository/UserDefaultsRepositoryImpl.swift b/MLS/Data/Data/Repository/UserDefaultsRepositoryImpl.swift index e665e03f..55a01487 100644 --- a/MLS/Data/Data/Repository/UserDefaultsRepositoryImpl.swift +++ b/MLS/Data/Data/Repository/UserDefaultsRepositoryImpl.swift @@ -49,7 +49,7 @@ public final class UserDefaultsRepositoryImpl: UserDefaultsRepository { return Disposables.create() } } - + public func removeAllSearch() -> Completable { return Completable.create { completable in var current = UserDefaults.standard.stringArray(forKey: self.recentSearchkey) ?? [] diff --git a/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchRemoveUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchRemoveUseCaseImpl.swift index d6959984..f130bd25 100644 --- a/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchRemoveUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchRemoveUseCaseImpl.swift @@ -5,7 +5,7 @@ import RxSwift public class RecentSearchRemoveUseCaseImpl: RecentSearchRemoveUseCase { var repository: UserDefaultsRepository - + public init(repository: UserDefaultsRepository) { self.repository = repository } @@ -13,7 +13,7 @@ public class RecentSearchRemoveUseCaseImpl: RecentSearchRemoveUseCase { public func remove(keyword: String) -> Completable { return repository.removeRecentSearch(keyword: keyword) } - + public func removeAll() -> Completable { return repository.removeAllSearch() } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift index 15b60e0b..c89a9695 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift @@ -418,4 +418,3 @@ extension DictionaryListViewController: UICollectionViewDelegate, UICollectionVi } } } - diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift index 75acf602..9d826ca9 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift @@ -249,7 +249,7 @@ extension DictionarySearchViewController: UICollectionViewDelegate, UICollection ) as? RecentSearchHeaderView else { return UICollectionViewCell() } guard let reactor = reactor else { return UICollectionViewCell() } - + view.deleteButton.rx.tap .map { Reactor.Action.deleteAllButtonTapped } .bind(to: reactor.action)