Skip to content

Commit f527923

Browse files
authored
Merge branch 'main' into feature/UploadDomainData
2 parents ed32a83 + 6632383 commit f527923

18 files changed

+2158
-1158
lines changed

HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj

Lines changed: 1057 additions & 1043 deletions
Large diffs are not rendered by default.

HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/Recipe.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,25 @@ struct Recipe {
1818
let likeCount: Int
1919
let createdAt: Date
2020
}
21+
22+
extension Recipe {
23+
24+
static func dummyRecipe() -> Recipe {
25+
.init(
26+
id: 1,
27+
type: .coffee,
28+
name: "",
29+
description: "",
30+
writer: .init(
31+
id: 1,
32+
profileImage: "",
33+
nickname: "",
34+
createdAt: Date()
35+
),
36+
imageUrls: [],
37+
isLikedByCurrentUser: false,
38+
likeCount: 0,
39+
createdAt: Date()
40+
)
41+
}
42+
}

HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeDetailInteractor.swift

Lines changed: 13 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,71 +6,43 @@
66
//
77

88
import Foundation
9+
910
import RxSwift
1011

1112
protocol RecipeDetailInteractorDelegate: AnyObject {
1213
func fetchedRecipe(result: Result<Recipe, Error>)
1314
}
1415

15-
protocol InputRecipeDetailInteractor {
16-
func viewDidLoad()
17-
}
18-
19-
protocol OutputRecipeDetailInteractor {
20-
var recipe: Observable<Result<Recipe, Error>> { get }
16+
protocol RecipeDetailInteractor {
17+
func viewDidLoad()
2118
}
2219

23-
class RecipeDetailInteractor: InputRecipeDetailInteractor, OutputRecipeDetailInteractor {
24-
20+
class RecipeDetailInteractorImpl: RecipeDetailInteractor {
21+
2522
private let fetchRecipeDetailUseCase: FetchRecipeDetailUseCase
2623
private let recipeID: Int
2724
private let disposeBag = DisposeBag()
28-
private let recipeDetailSubject = PublishSubject<Result<Recipe, Error>>()
2925
weak var delegate: RecipeDetailInteractorDelegate?
30-
31-
var recipe: Observable<Result<Recipe, Error>> {
32-
return recipeDetailSubject.asObservable()
33-
}
34-
26+
3527
init(
3628
fetchRecipeDetailUseCase: FetchRecipeDetailUseCase,
3729
recipeID: Int
3830
) {
3931
self.fetchRecipeDetailUseCase = fetchRecipeDetailUseCase
4032
self.recipeID = recipeID
4133
}
42-
43-
func setDelegate(_ delegate: RecipeDetailInteractorDelegate) {
44-
self.delegate = delegate
45-
bindOutputs()
46-
}
47-
48-
private func bindOutputs() {
49-
recipe
50-
.subscribe(onNext: { [weak self] result in
51-
self?.delegate?.fetchedRecipe(result: result)
52-
})
53-
.disposed(by: disposeBag)
54-
}
55-
34+
5635
func viewDidLoad() {
5736
fetchRecipeDetail()
5837
}
59-
38+
6039
private func fetchRecipeDetail() {
6140
fetchRecipeDetailUseCase.execute(recipeID: recipeID)
62-
.subscribe { [weak self] result in
63-
self?.handleResult(result)
64-
}
41+
.subscribe(onSuccess: { [weak self] result in
42+
self?.delegate?.fetchedRecipe(result: result)
43+
}, onFailure: { [weak self] error in
44+
self?.delegate?.fetchedRecipe(result: .failure(error))
45+
})
6546
.disposed(by: disposeBag)
6647
}
67-
68-
private func handleResult(_ result: Result<Recipe, Error>) {
69-
switch result {
70-
case .success(let recipe):
71-
self.recipeDetailSubject.onNext(.success(recipe))
72-
case .failure(let error):
73-
self.recipeDetailSubject.onNext(.failure(error))
74-
}
75-
}
7648
}

HomeCafeRecipes/HomeCafeRecipes/Domain/Interactor/RecipeListInteractor.swift

Lines changed: 25 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,28 @@
66
//
77

88
import Foundation
9+
910
import RxSwift
1011

1112
protocol RecipeListInteractorDelegate: AnyObject {
1213
func fetchedRecipes(result: Result<[Recipe], Error>)
1314
func showRecipeDetail(ID: Int)
1415
}
1516

16-
protocol InputRecipeListInteractor {
17+
protocol RecipeListInteractor {
1718
func viewDidLoad()
1819
func fetchNextPage()
1920
func didSelectItem(ID: Int)
2021
func searchRecipes(with query: String)
2122
func resetSearch()
2223
}
2324

24-
protocol OutputRecipeListInteractor {
25-
var recipes: Observable<Result<[Recipe], Error>> { get }
26-
}
27-
28-
class RecipeListInteractor: InputRecipeListInteractor, OutputRecipeListInteractor {
25+
class RecipeListInteractorImpl: RecipeListInteractor {
2926

3027
private let disposeBag = DisposeBag()
3128
private let fetchFeedListUseCase: FetchFeedListUseCase
3229
private let searchFeedListUseCase: SearchFeedListUseCase
33-
private weak var delegate: RecipeListInteractorDelegate?
30+
weak var delegate: RecipeListInteractorDelegate?
3431

3532
private var currentPage: Int = 1
3633
private var isFetching = false
@@ -40,34 +37,18 @@ class RecipeListInteractor: InputRecipeListInteractor, OutputRecipeListInteracto
4037

4138
private let recipesSubject = BehaviorSubject<Result<[Recipe], Error>>(value: .success([]))
4239

43-
var recipes: Observable<Result<[Recipe], Error>> {
44-
return recipesSubject.asObservable()
45-
}
46-
4740
init(fetchFeedListUseCase: FetchFeedListUseCase, searchFeedListUseCase: SearchFeedListUseCase) {
4841
self.fetchFeedListUseCase = fetchFeedListUseCase
4942
self.searchFeedListUseCase = searchFeedListUseCase
5043
}
51-
52-
func setDelegate(_ delegate: RecipeListInteractorDelegate) {
53-
self.delegate = delegate
54-
bindOutputs()
55-
}
56-
57-
private func bindOutputs() {
58-
recipes
59-
.subscribe(onNext: { [weak self] result in
60-
self?.delegate?.fetchedRecipes(result: result)
61-
})
62-
.disposed(by: disposeBag)
63-
}
64-
44+
6545
func viewDidLoad() {
6646
fetchRecipes()
6747
}
6848

6949
func fetchNextPage() {
70-
fetchNextRecipes(nextPage: currentPage)
50+
guard !isFetching else { return }
51+
fetchNextRecipes()
7152
}
7253

7354
func didSelectItem(ID: Int) {
@@ -78,6 +59,7 @@ class RecipeListInteractor: InputRecipeListInteractor, OutputRecipeListInteracto
7859
isSearching = false
7960
currentSearchQuery = nil
8061
currentPage = 1
62+
allRecipes.removeAll()
8163
recipesSubject.onNext(.success([]))
8264
fetchRecipes()
8365
}
@@ -89,29 +71,35 @@ class RecipeListInteractor: InputRecipeListInteractor, OutputRecipeListInteracto
8971
isSearching = true
9072
currentPage = 1
9173
searchFeedListUseCase.execute(title: title, pageNumber: currentPage)
92-
.subscribe { [weak self] result in
74+
.subscribe(onSuccess: { [weak self] result in
9375
self?.handleResult(result)
94-
}
76+
}, onFailure: { [weak self] error in
77+
self?.handleResult(.failure(error))
78+
})
9579
.disposed(by: disposeBag)
9680
}
9781

9882
private func fetchRecipes() {
9983
guard !isFetching else { return }
10084
isFetching = true
10185
fetchFeedListUseCase.execute(pageNumber: currentPage)
102-
.subscribe { [weak self] result in
86+
.subscribe(onSuccess: { [weak self] result in
10387
self?.handleResult(result)
104-
}
88+
}, onFailure: { [weak self] error in
89+
self?.handleResult(.failure(error))
90+
})
10591
.disposed(by: disposeBag)
10692
}
10793

108-
private func fetchNextRecipes(nextPage: Int) {
94+
private func fetchNextRecipes() {
10995
guard !isFetching else { return }
11096
isFetching = true
111-
fetchFeedListUseCase.execute(pageNumber: nextPage)
112-
.subscribe { [weak self] result in
97+
fetchFeedListUseCase.execute(pageNumber: currentPage)
98+
.subscribe(onSuccess: { [weak self] result in
11399
self?.handleResult(result)
114-
}
100+
}, onFailure: { [weak self] error in
101+
self?.handleResult(.failure(error))
102+
})
115103
.disposed(by: disposeBag)
116104
}
117105

@@ -127,11 +115,10 @@ class RecipeListInteractor: InputRecipeListInteractor, OutputRecipeListInteracto
127115
} else {
128116
allRecipes.append(contentsOf: recipes)
129117
}
130-
self.recipesSubject.onNext(.success(allRecipes))
131-
self.currentPage += 1
118+
delegate?.fetchedRecipes(result: .success(allRecipes))
119+
currentPage += 1
132120
case .failure(let error):
133-
recipesSubject.onNext(.failure(error))
121+
delegate?.fetchedRecipes(result: .failure(error))
134122
}
135123
}
136-
137124
}

HomeCafeRecipes/HomeCafeRecipes/Presentation/Feed/View/RecipeDetailViewController.swift

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ final class RecipeDetailViewController: UIViewController {
2020

2121
init(interactor: RecipeDetailInteractor) {
2222
self.interactor = interactor
23-
super.init(nibName: nil, bundle: nil)
24-
self.interactor.setDelegate(self)
23+
super.init(nibName: nil, bundle: nil)
2524
}
2625

2726
required init?(coder: NSCoder) {
@@ -37,7 +36,7 @@ final class RecipeDetailViewController: UIViewController {
3736
interactor.viewDidLoad()
3837
contentView.customNavigationBar.backButton.addTarget(self, action: #selector(backButtonTapped), for: .touchUpInside)
3938
}
40-
39+
4140
private func displayError(_ error: Error) {
4241
let alert = UIAlertController(title: "해당 레시피를 로드하는데 실패했습니다.", message: error.localizedDescription, preferredStyle: .alert)
4342
alert.addAction(UIAlertAction(title: "OK", style: .default))
@@ -60,7 +59,17 @@ extension RecipeDetailViewController: RecipeDetailInteractorDelegate {
6059
self.contentView.configure(with: recipeItemViewModel)
6160
}
6261
case .failure(let error):
63-
self.displayError(error)
62+
DispatchQueue.main.async {
63+
self.displayError(error)
64+
}
6465
}
6566
}
6667
}
68+
69+
70+
extension RecipeDetailViewController: Drawable {
71+
var viewController: UIViewController? {
72+
return self
73+
}
74+
}
75+

HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListView.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ final class RecipeListView: UIView {
2323
private let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
2424

2525
private var recipes: [RecipeListItemViewModel] = []
26-
weak var coordinator: RecipeDetailCoordinatorProtocol?
2726
weak var delegate: RecipeListViewDelegate?
2827

2928
override init(frame: CGRect) {

HomeCafeRecipes/HomeCafeRecipes/Presentation/FeedList/View/RecipeListViewController.swift

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ final class RecipeListViewController: UIViewController {
1313
private var recipes: [RecipeListItemViewModel] = []
1414
private let searchBar = SearchBar()
1515
private let recipeListView = RecipeListView()
16-
17-
init(interactor: RecipeListInteractor) {
18-
self.interactor = interactor
19-
super.init(nibName: nil, bundle: nil)
16+
private let recipeListMapper = RecipeListMapper()
17+
private let router: RecipeListRouter
18+
19+
init(interactor: RecipeListInteractor, router: RecipeListRouter) {
2020
self.interactor.setDelegate(self)
21-
21+
self.interactor = interactor
22+
self.router = router
23+
super.init(nibName: nil, bundle: nil)
2224
}
2325

2426
required init?(coder: NSCoder) {
@@ -27,7 +29,6 @@ final class RecipeListViewController: UIViewController {
2729

2830
override func viewDidLoad() {
2931
super.viewDidLoad()
30-
recipeListView.delegate = self
3132
setupUI()
3233
interactor.viewDidLoad()
3334
}
@@ -36,16 +37,16 @@ final class RecipeListViewController: UIViewController {
3637
view.backgroundColor = .white
3738
view.addSubview(searchBar)
3839
view.addSubview(recipeListView)
39-
40+
4041
searchBar.translatesAutoresizingMaskIntoConstraints = false
4142
recipeListView.translatesAutoresizingMaskIntoConstraints = false
42-
43+
4344
NSLayoutConstraint.activate([
4445
searchBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
4546
searchBar.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
4647
searchBar.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10),
4748
searchBar.heightAnchor.constraint(equalToConstant: 50),
48-
49+
4950
recipeListView.topAnchor.constraint(equalTo: searchBar.bottomAnchor),
5051
recipeListView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
5152
recipeListView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
@@ -54,10 +55,10 @@ final class RecipeListViewController: UIViewController {
5455

5556
searchBar.setDelegate(self)
5657
}
57-
5858
}
5959

6060
// MARK: - UISearchBarDelegate
61+
6162
extension RecipeListViewController: UISearchBarDelegate {
6263
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
6364
if searchText.isBlank {
@@ -75,6 +76,7 @@ extension RecipeListViewController: UISearchBarDelegate {
7576
}
7677

7778
// MARK: - RecipeListInteractorDelegate
79+
7880
extension RecipeListViewController: RecipeListInteractorDelegate {
7981
func fetchedRecipes(result: Result<[Recipe], Error>) {
8082
switch result {
@@ -90,7 +92,7 @@ extension RecipeListViewController: RecipeListInteractorDelegate {
9092
}
9193

9294
func showRecipeDetail(ID: Int) {
93-
coordinator.showRecipeDetail(from: self, recipeID: ID)
95+
router.navigateToRecipeDetail(from: self, recipeID: ID)
9496
}
9597
}
9698

@@ -100,7 +102,7 @@ extension RecipeListViewController: RecipeListViewDelegate {
100102
interactor.didSelectItem(ID: ID)
101103
}
102104

103-
func ScrollToBottom() {
105+
func scrollToBottom() {
104106
interactor.fetchNextPage()
105107
}
106108
}

0 commit comments

Comments
 (0)