Skip to content
This repository was archived by the owner on Dec 20, 2023. It is now read-only.

Commit 9fbab3a

Browse files
authored
Merge pull request #4 from miamib34ch/refactor_catalogMVP
Отрефакторил экран каталога под MVP
2 parents f7b983f + c79178e commit 9fbab3a

5 files changed

Lines changed: 153 additions & 53 deletions

File tree

AvitoTech-TraineeAssignment/AvitoTech-TraineeAssignment.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
8BC141342A9F8943000E26F3 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BC141332A9F8943000E26F3 /* String+Extension.swift */; };
3434
8BC692EE2A9FB9990096C00B /* Images.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BC692ED2A9FB9990096C00B /* Images.swift */; };
3535
8BC692F02A9FBE580096C00B /* SwipeNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BC692EF2A9FBE580096C00B /* SwipeNavigationController.swift */; };
36+
8BC692F22A9FD3850096C00B /* CatalogViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BC692F12A9FD3850096C00B /* CatalogViewPresenter.swift */; };
37+
8BC692F42A9FD48D0096C00B /* CatalogViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BC692F32A9FD48D0096C00B /* CatalogViewProtocol.swift */; };
3638
/* End PBXBuildFile section */
3739

3840
/* Begin PBXFileReference section */
@@ -63,6 +65,8 @@
6365
8BC141332A9F8943000E26F3 /* String+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = "<group>"; };
6466
8BC692ED2A9FB9990096C00B /* Images.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Images.swift; sourceTree = "<group>"; };
6567
8BC692EF2A9FBE580096C00B /* SwipeNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeNavigationController.swift; sourceTree = "<group>"; };
68+
8BC692F12A9FD3850096C00B /* CatalogViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CatalogViewPresenter.swift; sourceTree = "<group>"; };
69+
8BC692F32A9FD48D0096C00B /* CatalogViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CatalogViewProtocol.swift; sourceTree = "<group>"; };
6670
/* End PBXFileReference section */
6771

6872
/* Begin PBXFrameworksBuildPhase section */
@@ -189,7 +193,9 @@
189193
8BC141252A9E6AD5000E26F3 /* Catalog */ = {
190194
isa = PBXGroup;
191195
children = (
196+
8BC692F32A9FD48D0096C00B /* CatalogViewProtocol.swift */,
192197
8B1C9AC32A9A7D0B00127D1F /* CatalogViewController.swift */,
198+
8BC692F12A9FD3850096C00B /* CatalogViewPresenter.swift */,
193199
8BC141292A9E6F4E000E26F3 /* CatalogCell.swift */,
194200
);
195201
path = Catalog;
@@ -321,11 +327,13 @@
321327
8BC118BF2A9D06CF00ABE6C9 /* CatalogsObjectNetworkService.swift in Sources */,
322328
8BC141342A9F8943000E26F3 /* String+Extension.swift in Sources */,
323329
8B1C9AC02A9A7D0B00127D1F /* AppDelegate.swift in Sources */,
330+
8BC692F42A9FD48D0096C00B /* CatalogViewProtocol.swift in Sources */,
324331
8B1C9AC22A9A7D0B00127D1F /* SceneDelegate.swift in Sources */,
325332
8BC118B92A9CF8EA00ABE6C9 /* CatalogNetworkService.swift in Sources */,
326333
8BC118B52A9CF71C00ABE6C9 /* CatalogRequest.swift in Sources */,
327334
8BC118A82A9CB4CC00ABE6C9 /* CatalogModel.swift in Sources */,
328335
8BC692EE2A9FB9990096C00B /* Images.swift in Sources */,
336+
8BC692F22A9FD3850096C00B /* CatalogViewPresenter.swift in Sources */,
329337
8BC118AE2A9CC04300ABE6C9 /* NetworkClient.swift in Sources */,
330338
8BC141322A9F7C72000E26F3 /* UIBlockingProgressHUD.swift in Sources */,
331339
);

AvitoTech-TraineeAssignment/AvitoTech-TraineeAssignment/SceneDelegate.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,17 @@ import UIKit
99

1010
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
1111
var window: UIWindow?
12+
var catalogViewController: CatalogViewController {
13+
let presenter = CatalogViewPresenter()
14+
let catalogViewController = CatalogViewController(presenter: presenter)
15+
presenter.injectViewController(viewController: catalogViewController)
16+
return catalogViewController
17+
}
1218

1319
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
1420
guard let windowScene = (scene as? UIWindowScene) else { return }
1521
window = UIWindow(windowScene: windowScene)
16-
window?.rootViewController = SwipeNavigationController(rootViewController: CatalogViewController())
22+
window?.rootViewController = SwipeNavigationController(rootViewController: catalogViewController)
1723
window?.makeKeyAndVisible()
1824
}
1925
}

AvitoTech-TraineeAssignment/AvitoTech-TraineeAssignment/Screens/Catalog/CatalogViewController.swift

Lines changed: 40 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,20 @@
77

88
import UIKit
99

10-
class CatalogViewController: UIViewController {
10+
final class CatalogViewController: UIViewController, CatalogViewControllerProtocol {
11+
private var presenter: CatalogViewPresenterProtocol
12+
1113
private let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
1214
private let refreshControl = UIRefreshControl()
1315

14-
private let catalogNetworkService = CatalogNetworkService.shared
15-
private var catalogNetworkServiceObserverData: NSObjectProtocol?
16-
private var catalogNetworkServiceObserverError: NSObjectProtocol?
16+
init(presenter: CatalogViewPresenterProtocol) {
17+
self.presenter = presenter
18+
super.init(nibName: nil, bundle: nil)
19+
}
20+
21+
required init?(coder: NSCoder) {
22+
fatalError("init(coder:) has not been implemented")
23+
}
1724

1825
override func viewDidLoad() {
1926
super.viewDidLoad()
@@ -22,23 +29,32 @@ class CatalogViewController: UIViewController {
2229
configureCollection()
2330
configureRefreshControl()
2431

25-
catalogNetworkServiceObserverData = NotificationCenter.default
26-
.addObserver(
27-
forName: CatalogNetworkService.dataReceivedNotification,
28-
object: nil,
29-
queue: .main
30-
) { [weak self] _ in
31-
self?.updateCollection()
32-
}
33-
catalogNetworkServiceObserverError = NotificationCenter.default
34-
.addObserver(
35-
forName: CatalogNetworkService.errorNotification,
36-
object: nil,
37-
queue: .main
38-
) { [weak self] _ in
39-
self?.showAlert()
40-
}
41-
loadData()
32+
presenter.viewDidLoad()
33+
}
34+
35+
func updateCollection() {
36+
collectionView.reloadData()
37+
}
38+
39+
func showAlert(alert: UIAlertController) {
40+
present(alert, animated: true)
41+
}
42+
43+
func showHud() {
44+
UIBlockingProgressHUD.show()
45+
}
46+
47+
func removeHud() {
48+
UIBlockingProgressHUD.dismiss()
49+
}
50+
51+
func configureCell(cell: CatalogCell, with model: Advertisement) {
52+
cell.id = model.id
53+
cell.setImage(link: URL(string: model.imageURL))
54+
cell.setNameLabel(name: model.title)
55+
cell.setCostLabel(cost: model.price)
56+
cell.adressLabel(adress: model.location)
57+
cell.dateLabel(date: model.createdDate)
4258
}
4359

4460
private func configureCollection() {
@@ -65,31 +81,9 @@ class CatalogViewController: UIViewController {
6581
refreshControl.addTarget(self, action: #selector(pullToRefresh), for: .valueChanged)
6682
}
6783

68-
private func updateCollection() {
69-
UIBlockingProgressHUD.dismiss()
70-
collectionView.reloadData()
71-
}
72-
73-
private func showAlert() {
74-
UIBlockingProgressHUD.dismiss()
75-
let alertTitle = NSLocalizedString("alert.title", comment: "Название алерта")
76-
let alertMessage = NSLocalizedString("alert.message", comment: "Сообщение в алерте")
77-
let alertActionTitle = NSLocalizedString("alert.action.again", comment: "Название действия повторения в алерте")
78-
let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: .alert)
79-
alert.addAction(UIAlertAction(title: alertActionTitle, style: .default) { [weak self] _ in
80-
self?.loadData()
81-
})
82-
present(alert, animated: true)
83-
}
84-
85-
private func loadData() {
86-
UIBlockingProgressHUD.show()
87-
catalogNetworkService.fetch()
88-
}
89-
9084
@objc private func pullToRefresh() {
9185
refreshControl.endRefreshing()
92-
loadData()
86+
presenter.viewDidPullToRefresh()
9387
}
9488
}
9589

@@ -115,18 +109,12 @@ extension CatalogViewController: UICollectionViewDataSource {
115109
}
116110

117111
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
118-
catalogNetworkService.catalogModel?.advertisements.count ?? 0
112+
presenter.numberOfAdvertisement
119113
}
120114

121115
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
122116
let cell: CatalogCell = collectionView.dequeueReusableCell(indexPath: indexPath)
123-
guard let model = catalogNetworkService.catalogModel?.advertisements[indexPath.row] else { return cell }
124-
cell.id = model.id
125-
cell.setImage(link: URL(string: model.imageURL))
126-
cell.setNameLabel(name: model.title)
127-
cell.setCostLabel(cost: model.price)
128-
cell.adressLabel(adress: model.location)
129-
cell.dateLabel(date: model.createdDate)
117+
presenter.viewWillConfigureCell(cell: cell, with: indexPath)
130118
return cell
131119
}
132120

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//
2+
// CatalogViewPresenter.swift
3+
// AvitoTech-TraineeAssignment
4+
//
5+
// Created by Богдан Полыгалов on 31.08.2023.
6+
//
7+
8+
import UIKit
9+
10+
final class CatalogViewPresenter: CatalogViewPresenterProtocol {
11+
var numberOfAdvertisement: Int {
12+
catalogNetworkService.catalogModel?.advertisements.count ?? 0
13+
}
14+
15+
weak private var viewController: CatalogViewControllerProtocol?
16+
private let catalogNetworkService = CatalogNetworkService.shared
17+
private var catalogNetworkServiceObserverData: NSObjectProtocol?
18+
private var catalogNetworkServiceObserverError: NSObjectProtocol?
19+
20+
func injectViewController(viewController: CatalogViewControllerProtocol) {
21+
self.viewController = viewController
22+
}
23+
24+
func viewDidLoad() {
25+
catalogNetworkServiceObserverData = NotificationCenter.default
26+
.addObserver(
27+
forName: CatalogNetworkService.dataReceivedNotification,
28+
object: nil,
29+
queue: .main
30+
) { [weak self] _ in
31+
self?.updateViewCollection()
32+
}
33+
catalogNetworkServiceObserverError = NotificationCenter.default
34+
.addObserver(
35+
forName: CatalogNetworkService.errorNotification,
36+
object: nil,
37+
queue: .main
38+
) { [weak self] _ in
39+
self?.showViewAlert()
40+
}
41+
loadData()
42+
}
43+
44+
func viewDidPullToRefresh() {
45+
loadData()
46+
}
47+
48+
func viewWillConfigureCell(cell: CatalogCell, with indexPath: IndexPath) {
49+
guard let model = catalogNetworkService.catalogModel?.advertisements[indexPath.row] else { return }
50+
viewController?.configureCell(cell: cell, with: model)
51+
}
52+
53+
private func updateViewCollection() {
54+
viewController?.removeHud()
55+
viewController?.updateCollection()
56+
}
57+
58+
private func showViewAlert() {
59+
viewController?.removeHud()
60+
let alertTitle = NSLocalizedString("alert.title", comment: "Название алерта")
61+
let alertMessage = NSLocalizedString("alert.message", comment: "Сообщение в алерте")
62+
let alertActionTitle = NSLocalizedString("alert.action.again", comment: "Название действия повторения в алерте")
63+
let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: .alert)
64+
alert.addAction(UIAlertAction(title: alertActionTitle, style: .default) { [weak self] _ in
65+
self?.loadData()
66+
})
67+
viewController?.showAlert(alert: alert)
68+
}
69+
70+
private func loadData() {
71+
viewController?.showHud()
72+
catalogNetworkService.fetch()
73+
}
74+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//
2+
// CatalogViewProtocol.swift
3+
// AvitoTech-TraineeAssignment
4+
//
5+
// Created by Богдан Полыгалов on 31.08.2023.
6+
//
7+
8+
import UIKit
9+
10+
protocol CatalogViewPresenterProtocol {
11+
var numberOfAdvertisement: Int { get }
12+
func injectViewController(viewController: CatalogViewControllerProtocol)
13+
func viewDidLoad()
14+
func viewDidPullToRefresh()
15+
func viewWillConfigureCell(cell: CatalogCell, with indexPath: IndexPath)
16+
}
17+
18+
protocol CatalogViewControllerProtocol: AnyObject {
19+
func updateCollection()
20+
func showAlert(alert: UIAlertController)
21+
func showHud()
22+
func removeHud()
23+
func configureCell(cell: CatalogCell, with model: Advertisement)
24+
}

0 commit comments

Comments
 (0)