201 lines
5.1 KiB
Swift

//
// AppDelegate.swift
// ReviewsFeed
//
// Created by Dmitrii Ivanov on 21/07/2020.
// Copyright © 2020 ING. All rights reserved.
//
import Combine
import ReviewsUIKit
import SwiftUI
import UIKit
public class FeedViewController: UITableViewController {
// MARK: Constants
private let viewModel: ViewModel
// MARK: Properties
private var cancellables: Set<AnyCancellable> = []
// MARK: Initialisers
public init(configuration: Configuration = .init()) {
self.viewModel = .init(configuration: configuration)
super.init(style: .plain)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: UIViewController
public override func viewDidLoad() {
super.viewDidLoad()
tableView.register(
UITableViewCell.self,
forCellReuseIdentifier: .Cell.feedItem
)
bindViewModel()
viewModel.fetch()
}
// MARK: UITableViewDataSource
public override func tableView(
_ tableView: UITableView,
numberOfRowsInSection section: Int
) -> Int {
viewModel.items.count
}
public override func tableView(
_ tableView: UITableView,
cellForRowAt indexPath: IndexPath
) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: .Cell.feedItem) else {
return .init()
}
cell.contentConfiguration = {
if #available(iOS 16.0, *) {
UIHostingConfiguration {
FeedItemCell(viewModel.items[indexPath.row])
}
} else {
HostingConfiguration {
FeedItemCell(viewModel.items[indexPath.row])
}
}
}()
return cell
}
// MARK: UITableViewDelegate
public override func tableView(
_ tableView: UITableView,
didSelectRowAt indexPath: IndexPath
) {
let details = DetailsViewController(viewModel.items[indexPath.row])
tableView.deselectRow(
at: indexPath,
animated: true
)
navigationController?.pushViewController(details, animated: true)
}
}
// MARK: - Helpers
private extension FeedViewController {
// MARK: Functions
func bindViewModel() {
viewModel.$loading
.sink { loading in
print("LOADING: \(loading)")
}
.store(in: &cancellables)
viewModel.$loading
.dropFirst()
.filter { $0 == false }
.receive(on: RunLoop.main)
.sink { [weak self] _ in
self?.tableView.reloadData()
}
.store(in: &cancellables)
}
}
// MARK: - Configuration
extension FeedViewController {
public struct Configuration {
// MARK: Constants
let appID: String
let countryCode: String
let session: URLSessionConfiguration
// MARK: Initialisers
public init(
appID: String = "474495017",
countryCode: String = "nl",
session: URLSessionConfiguration = .ephemeral
) {
self.appID = appID
self.countryCode = countryCode
self.session = session
}
}
}
// MARK: - String+Constants
private extension String {
enum Cell {
static let feedItem = "FeedItemCell"
}
}
// MARK: - Previews
#if DEBUG
import ReviewsFoundationKit
import ReviewsiTunesKit
@available(iOS 17.0, *)
#Preview("Feed View Controller with few reviews") {
MockURLProtocol.response = .init(
statusCode: 200,
object: Feed(entries: [
.init(
id: 1,
author: "Some author name #1 here",
title: "Some review title #1 goes here...",
content: "Some long, explanatory review comment #1 goes here...",
rating: 3,
version: "v1.0.0",
updated: .init()
),
.init(
id: 2,
author: "Some author name #2 here",
title: "Some review title #2 goes here...",
content: "Some long, explanatory review comment #2 goes here...",
rating: 5,
version: "v1.0.0",
updated: .init()
),
.init(
id: 3,
author: "Some author name #3 here",
title: "Some review title #3 goes here...",
content: "Some long, explanatory review comment #3 goes here...",
rating: 1,
version: "v1.0.0",
updated: .init()
),
])
)
return FeedViewController(configuration: .init(session: .mock))
}
@available(iOS 17.0, *)
#Preview("Feed View Controller with no reviews") {
MockURLProtocol.response = .init(
statusCode: 200,
object: Feed(entries: [])
)
return FeedViewController(configuration: .init(session: .mock))
}
#endif