Commit 70fa2157 authored by Alex Klovak's avatar Alex Klovak
Browse files

added horizontal list to table view

parent b7b895fc
......@@ -37,6 +37,14 @@
0857B06524A3786800A09E7E /* LoadingCollectionCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0857B06424A3786800A09E7E /* LoadingCollectionCellViewModel.swift */; };
0857B06724A378AD00A09E7E /* LoadingCollectionCellViewModelInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0857B06624A378AD00A09E7E /* LoadingCollectionCellViewModelInterface.swift */; };
0857B06924A37B3300A09E7E /* CellViewModelInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0857B06824A37B3300A09E7E /* CellViewModelInterface.swift */; };
0857B06B24A49B2C00A09E7E /* HorizontalListTableCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0857B06A24A49B2C00A09E7E /* HorizontalListTableCellViewModel.swift */; };
0857B06D24A49B8A00A09E7E /* HorizontalListTableCellViewModelInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0857B06C24A49B8A00A09E7E /* HorizontalListTableCellViewModelInterface.swift */; };
0857B06F24A4C4B500A09E7E /* HorizontalListTableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0857B06E24A4C4B500A09E7E /* HorizontalListTableCell.swift */; };
0857B07124A4C4C400A09E7E /* HorizontalListTableCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0857B07024A4C4C400A09E7E /* HorizontalListTableCell.xib */; };
0857B07324A5F58700A09E7E /* FeaturedNewsCollectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0857B07224A5F58700A09E7E /* FeaturedNewsCollectionCell.swift */; };
0857B07524A5F59400A09E7E /* FeaturedNewsCollectionCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0857B07424A5F59400A09E7E /* FeaturedNewsCollectionCell.xib */; };
0857B07724A61D9900A09E7E /* FeaturedNewsCollectionCellViewModelInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0857B07624A61D9900A09E7E /* FeaturedNewsCollectionCellViewModelInterface.swift */; };
0857B07924A61F7B00A09E7E /* FeaturedNewsCollectionCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0857B07824A61F7B00A09E7E /* FeaturedNewsCollectionCellViewModel.swift */; };
08BE53D524A238B100C6489E /* LoadingCollectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08BE53D424A238B100C6489E /* LoadingCollectionCell.swift */; };
08BE53D724A238BD00C6489E /* LoadingCollectionCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 08BE53D624A238BD00C6489E /* LoadingCollectionCell.xib */; };
08BE53D924A23C1100C6489E /* NewsCellViewModelInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08BE53D824A23C1100C6489E /* NewsCellViewModelInterface.swift */; };
......@@ -113,6 +121,14 @@
0857B06424A3786800A09E7E /* LoadingCollectionCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingCollectionCellViewModel.swift; sourceTree = "<group>"; };
0857B06624A378AD00A09E7E /* LoadingCollectionCellViewModelInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingCollectionCellViewModelInterface.swift; sourceTree = "<group>"; };
0857B06824A37B3300A09E7E /* CellViewModelInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CellViewModelInterface.swift; sourceTree = "<group>"; };
0857B06A24A49B2C00A09E7E /* HorizontalListTableCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HorizontalListTableCellViewModel.swift; sourceTree = "<group>"; };
0857B06C24A49B8A00A09E7E /* HorizontalListTableCellViewModelInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HorizontalListTableCellViewModelInterface.swift; sourceTree = "<group>"; };
0857B06E24A4C4B500A09E7E /* HorizontalListTableCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HorizontalListTableCell.swift; sourceTree = "<group>"; };
0857B07024A4C4C400A09E7E /* HorizontalListTableCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HorizontalListTableCell.xib; sourceTree = "<group>"; };
0857B07224A5F58700A09E7E /* FeaturedNewsCollectionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeaturedNewsCollectionCell.swift; sourceTree = "<group>"; };
0857B07424A5F59400A09E7E /* FeaturedNewsCollectionCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FeaturedNewsCollectionCell.xib; sourceTree = "<group>"; };
0857B07624A61D9900A09E7E /* FeaturedNewsCollectionCellViewModelInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeaturedNewsCollectionCellViewModelInterface.swift; sourceTree = "<group>"; };
0857B07824A61F7B00A09E7E /* FeaturedNewsCollectionCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeaturedNewsCollectionCellViewModel.swift; sourceTree = "<group>"; };
08BE53D424A238B100C6489E /* LoadingCollectionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingCollectionCell.swift; sourceTree = "<group>"; };
08BE53D624A238BD00C6489E /* LoadingCollectionCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LoadingCollectionCell.xib; sourceTree = "<group>"; };
08BE53D824A23C1100C6489E /* NewsCellViewModelInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsCellViewModelInterface.swift; sourceTree = "<group>"; };
......@@ -234,6 +250,10 @@
080B6FE824A216C600E99774 /* NewsCollectionCell.xib */,
08BE53D424A238B100C6489E /* LoadingCollectionCell.swift */,
08BE53D624A238BD00C6489E /* LoadingCollectionCell.xib */,
0857B06E24A4C4B500A09E7E /* HorizontalListTableCell.swift */,
0857B07024A4C4C400A09E7E /* HorizontalListTableCell.xib */,
0857B07224A5F58700A09E7E /* FeaturedNewsCollectionCell.swift */,
0857B07424A5F59400A09E7E /* FeaturedNewsCollectionCell.xib */,
);
path = Cells;
sourceTree = "<group>";
......@@ -245,6 +265,8 @@
0800754C249A06480091FE21 /* LoadingTableCellViewModel.swift */,
080B6FEC24A2176D00E99774 /* NewsCollectionCellViewModel.swift */,
0857B06424A3786800A09E7E /* LoadingCollectionCellViewModel.swift */,
0857B06A24A49B2C00A09E7E /* HorizontalListTableCellViewModel.swift */,
0857B07824A61F7B00A09E7E /* FeaturedNewsCollectionCellViewModel.swift */,
);
path = ViewModels;
sourceTree = "<group>";
......@@ -392,6 +414,8 @@
080B6FEA24A216F300E99774 /* NewsCollectionCellViewModelInterface.swift */,
08BE53D824A23C1100C6489E /* NewsCellViewModelInterface.swift */,
0857B06624A378AD00A09E7E /* LoadingCollectionCellViewModelInterface.swift */,
0857B06C24A49B8A00A09E7E /* HorizontalListTableCellViewModelInterface.swift */,
0857B07624A61D9900A09E7E /* FeaturedNewsCollectionCellViewModelInterface.swift */,
);
path = Interfaces;
sourceTree = "<group>";
......@@ -540,8 +564,10 @@
08C98373249226B200D6B570 /* LaunchScreen.storyboard in Resources */,
08C98370249226B200D6B570 /* Assets.xcassets in Resources */,
0800754B249A05C80091FE21 /* LoadingTableCell.xib in Resources */,
0857B07524A5F59400A09E7E /* FeaturedNewsCollectionCell.xib in Resources */,
08C9836B249226B100D6B570 /* Main.storyboard in Resources */,
080B6FE924A216C600E99774 /* NewsCollectionCell.xib in Resources */,
0857B07124A4C4C400A09E7E /* HorizontalListTableCell.xib in Resources */,
0816B6BC24978F6400BD4525 /* NewsTableCell.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
......@@ -655,7 +681,9 @@
files = (
080B6FDD24A0F61800E99774 /* NewsTableCellFabric.swift in Sources */,
0816B6C02497937A00BD4525 /* NewsTableCellViewModel.swift in Sources */,
0857B07724A61D9900A09E7E /* FeaturedNewsCollectionCellViewModelInterface.swift in Sources */,
08C98368249226B100D6B570 /* NewsListViewController.swift in Sources */,
0857B06B24A49B2C00A09E7E /* HorizontalListTableCellViewModel.swift in Sources */,
08C98364249226B100D6B570 /* AppDelegate.swift in Sources */,
08C983A524924B4500D6B570 /* UIView+Extension.swift in Sources */,
08007545249A038D0091FE21 /* TableCellIViewModelnterface.swift in Sources */,
......@@ -666,12 +694,14 @@
0800754D249A06480091FE21 /* LoadingTableCellViewModel.swift in Sources */,
08C983AA2492651200D6B570 /* NewsListTableController.swift in Sources */,
08007558249B77A50091FE21 /* NewsRequestModel.swift in Sources */,
0857B06D24A49B8A00A09E7E /* HorizontalListTableCellViewModelInterface.swift in Sources */,
0857B06524A3786800A09E7E /* LoadingCollectionCellViewModel.swift in Sources */,
080B6FE524A2163E00E99774 /* CollectionCellViewModelInterface.swift in Sources */,
08007549249A05BE0091FE21 /* LoadingTableCell.swift in Sources */,
0857B06924A37B3300A09E7E /* CellViewModelInterface.swift in Sources */,
0816B6BA24978F5800BD4525 /* NewsTableCell.swift in Sources */,
08007550249A45430091FE21 /* TableHeaderView.swift in Sources */,
0857B06F24A4C4B500A09E7E /* HorizontalListTableCell.swift in Sources */,
0816B6B624978F1700BD4525 /* NewsTableCellViewModelInterface.swift in Sources */,
08C983B024936BD200D6B570 /* NewsListControllerInterface.swift in Sources */,
080B6FDF24A2100B00E99774 /* NewsCollectionCellFabric.swift in Sources */,
......@@ -689,10 +719,12 @@
0816B6B424976ABA00BD4525 /* NetworkManager.swift in Sources */,
08C9836E249226B100D6B570 /* NewsListModule.xcdatamodeld in Sources */,
08C983A324924B0400D6B570 /* NewsListModel.swift in Sources */,
0857B07924A61F7B00A09E7E /* FeaturedNewsCollectionCellViewModel.swift in Sources */,
08C983A1249248A000D6B570 /* NewsModelInterface.swift in Sources */,
080B6FE124A215B700E99774 /* BaseCollectionCell.swift in Sources */,
08C983AC2492652900D6B570 /* NewsListControllerDelegate.swift in Sources */,
080B6FDA24A0CE1000E99774 /* BaseTableCell.swift in Sources */,
0857B07324A5F58700A09E7E /* FeaturedNewsCollectionCell.swift in Sources */,
0816B6BE249790F700BD4525 /* NewsTableCellInterface.swift in Sources */,
08C98366249226B100D6B570 /* SceneDelegate.swift in Sources */,
08C983AE2493625700D6B570 /* Dictionary+Extension.swift in Sources */,
......
......@@ -15,6 +15,10 @@ class NewsTableCellFabric {
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: NewsTableCell.self)) as! NewsTableCell
cell.fill(with: _viewModel)
return cell
} else if let _viewModel = viewModel as? HorizontalListTableCellViewModelInterface {
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: HorizontalListTableCell.self)) as! HorizontalListTableCell
cell.fill(with: _viewModel)
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: LoadingTableCell.self)) as! LoadingTableCell
return cell
......
//
// FeaturedNewsCollectionCell.swift
// NewsListModule
//
// Created by Sasha Klovak on 6/26/20.
// Copyright © 2020 Triare. All rights reserved.
//
import UIKit
import Kingfisher
class FeaturedNewsCollectionCell: BaseCollectionCell {
@IBOutlet weak var backgroundImageView: UIImageView!
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var subtitleLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func fill(with viewModel: CollectionCellViewModelInterface) {
guard let _viewModel = viewModel as? FeaturedNewsCollectionCellViewModelInterface else { return }
backgroundImageView.kf.setImage(with: _viewModel.imageURL)
titleLabel.text = _viewModel.title
subtitleLabel.text = _viewModel.subtitle
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15400" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15404"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="FeaturedNewsCollectionCell" customModule="NewsListModule" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="414" height="220"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="bWk-AH-Bua">
<rect key="frame" x="0.0" y="0.0" width="414" height="220"/>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="LFH-fV-XEm">
<rect key="frame" x="0.0" y="132" width="414" height="88"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OTt-fe-adq">
<rect key="frame" x="10" y="10" width="394" height="18"/>
<constraints>
<constraint firstAttribute="height" constant="18" id="hXc-zD-XBF"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="InC-4m-5kg">
<rect key="frame" x="10" y="38" width="394" height="36"/>
<constraints>
<constraint firstAttribute="height" constant="36" id="3oA-Mu-Ch2"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="0.5" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="InC-4m-5kg" firstAttribute="leading" secondItem="LFH-fV-XEm" secondAttribute="leading" constant="10" id="0wC-ru-qGn"/>
<constraint firstItem="InC-4m-5kg" firstAttribute="top" secondItem="OTt-fe-adq" secondAttribute="bottom" constant="10" id="FZL-sa-iQS"/>
<constraint firstAttribute="trailing" secondItem="InC-4m-5kg" secondAttribute="trailing" constant="10" id="MeC-he-not"/>
<constraint firstAttribute="trailing" secondItem="OTt-fe-adq" secondAttribute="trailing" constant="10" id="dqu-p9-pNz"/>
<constraint firstItem="OTt-fe-adq" firstAttribute="top" secondItem="LFH-fV-XEm" secondAttribute="top" constant="10" id="lNm-1C-pKA"/>
<constraint firstAttribute="height" constant="88" id="s4O-Kl-GKL"/>
<constraint firstItem="OTt-fe-adq" firstAttribute="leading" secondItem="LFH-fV-XEm" secondAttribute="leading" constant="10" id="ynL-cE-ZkK"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="bWk-AH-Bua" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="Cvq-Aa-qji"/>
<constraint firstItem="LFH-fV-XEm" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="HkE-OG-kOK"/>
<constraint firstItem="bWk-AH-Bua" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="WGI-e5-1Kt"/>
<constraint firstItem="bWk-AH-Bua" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="a0u-d9-2TF"/>
<constraint firstItem="LFH-fV-XEm" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="hU3-62-SB3"/>
<constraint firstItem="bWk-AH-Bua" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="qU7-2Z-vc3"/>
<constraint firstItem="LFH-fV-XEm" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="yUL-jZ-kJx"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<connections>
<outlet property="backgroundImageView" destination="bWk-AH-Bua" id="hwF-Fx-3na"/>
<outlet property="subtitleLabel" destination="InC-4m-5kg" id="lhi-Sc-LiB"/>
<outlet property="titleLabel" destination="OTt-fe-adq" id="Aqs-y5-Tz6"/>
</connections>
<point key="canvasLocation" x="137.68115942028987" y="372.32142857142856"/>
</view>
</objects>
</document>
//
// HorizontalListCollectionCell.swift
// NewsListModule
//
// Created by Sasha Klovak on 6/25/20.
// Copyright © 2020 Triare. All rights reserved.
//
import UIKit
class HorizontalListTableCell: BaseTableCell {
@IBOutlet weak var collectionView: UICollectionView!
private var viewModel: HorizontalListTableCellViewModelInterface?
var onDidPresItem: ((IndexPath) -> Void)?
override func awakeFromNib() {
super.awakeFromNib()
prepareCollectionView()
}
private func prepareCollectionView() {
collectionView.delegate = self
collectionView.dataSource = self
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.register(UINib(nibName: String(describing: FeaturedNewsCollectionCell.self), bundle: nil), forCellWithReuseIdentifier: String(describing: FeaturedNewsCollectionCell.self))
}
override func fill(with viewModel: TableCellViewModelInterface) {
guard let _viewModel = viewModel as? HorizontalListTableCellViewModelInterface else { return }
self.viewModel = _viewModel
collectionView.reloadData()
}
}
extension HorizontalListTableCell: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return viewModel?.cellViewModels?.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return viewModel?.cellViewModels?[indexPath.item].cellSize() ?? CGSize.zero
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: FeaturedNewsCollectionCell.self), for: indexPath) as! FeaturedNewsCollectionCell
if let _viewModel = viewModel?.cellViewModels?[indexPath.item] as? FeaturedNewsCollectionCellViewModelInterface {
cell.fill(with: _viewModel)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let block = onDidPresItem else { return }
block(indexPath)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets.zero
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15400" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15404"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="HorizontalListTableCell" customModule="NewsListModule" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="414" height="274"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="none" translatesAutoresizingMaskIntoConstraints="NO" id="B7K-dq-7E5">
<rect key="frame" x="0.0" y="0.0" width="414" height="274"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="10" id="XfB-Ev-khz">
<size key="itemSize" width="50" height="50"/>
<size key="estimatedItemSize" width="50" height="50"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
</collectionView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="B7K-dq-7E5" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="Bbt-bh-f9a"/>
<constraint firstItem="B7K-dq-7E5" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="LVe-Ii-V13"/>
<constraint firstItem="B7K-dq-7E5" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="a7B-7W-NcZ"/>
<constraint firstItem="B7K-dq-7E5" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="kmB-tc-WZv"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<connections>
<outlet property="collectionView" destination="B7K-dq-7E5" id="UAq-d3-1gK"/>
</connections>
<point key="canvasLocation" x="137.68115942028987" y="361.60714285714283"/>
</view>
</objects>
</document>
......@@ -15,7 +15,6 @@ class NewsListCollectionController: NSObject, NewsListControllerInterface {
var contentView: UIView?
var cellViewModels: [CellViewModelInterface]?
private var models: [NewsModel] = []
private let contentLoader = ContentLoader(limit: 20)
init(parentView: UIView, collectionDelegate: UICollectionViewDelegate, collectionDataSource: UICollectionViewDataSource, delegate: NewsListControllerDelegate) {
......@@ -49,7 +48,6 @@ class NewsListCollectionController: NSObject, NewsListControllerInterface {
var viewModel = NewsCollectionCellViewModel()
viewModel.update(for: newsModel)
cellViewModels?.append(viewModel)
models.append(newsModel)
}
contentLoader.addLoadedCount(model.articles?.count ?? 0)
} else {
......@@ -57,6 +55,9 @@ class NewsListCollectionController: NSObject, NewsListControllerInterface {
}
}
func prepareFeaturedCellViewModels(_ listModel: NewsListModel?, error: Error?) {
}
func startLoading() {
contentLoader.startLoading()
if cellViewModels?.count ?? 0 > 0 {
......
......@@ -10,12 +10,13 @@ import UIKit
class NewsListTableController: NSObject, NewsListControllerInterface {
var networkManager: NetworkManager?
weak var delegate: NewsListControllerDelegate?
var contentView: UIView?
var cellViewModels: [CellViewModelInterface]?
private var models: [NewsModel] = []
var featuredCellViewModels: [CellViewModelInterface]?
private let contentLoader = ContentLoader(limit: 20)
init(parentView: UIView, tableDelegate: UITableViewDelegate, tableDataSource: UITableViewDataSource, delegate: NewsListControllerDelegate) {
......@@ -32,9 +33,11 @@ class NewsListTableController: NSObject, NewsListControllerInterface {
tableView.register(UINib(nibName: String(describing: NewsTableCell.self), bundle: nil), forCellReuseIdentifier: String(describing: NewsTableCell.self))
tableView.register(UINib(nibName: String(describing: LoadingTableCell.self), bundle: nil), forCellReuseIdentifier: String(describing: LoadingTableCell.self))
tableView.register(UINib(nibName: String(describing: HorizontalListTableCell.self), bundle: nil), forCellReuseIdentifier: String(describing: HorizontalListTableCell.self))
cellViewModels = []
loadData(contentLoader)
loadFeaturedData()
}
func startLoading() {
......@@ -60,7 +63,6 @@ class NewsListTableController: NSObject, NewsListControllerInterface {
var viewModel = NewsTableCellViewModel()
viewModel.update(for: newsModel)
cellViewModels?.append(viewModel)
models.append(newsModel)
}
contentLoader.addLoadedCount(model.articles?.count ?? 0)
} else {
......@@ -68,6 +70,21 @@ class NewsListTableController: NSObject, NewsListControllerInterface {
}
}
func prepareFeaturedCellViewModels(_ listModel: NewsListModel?, error: Error?) {
if let model = listModel {
if model.articles?.count ?? 0 > 0 {
let viewModel = HorizontalListTableCellViewModel()
viewModel.cellViewModels = []
for newsModel in model.articles ?? [] {
var cellViewModel = FeaturedNewsCollectionCellViewModel()
cellViewModel.update(for: newsModel)
viewModel.cellViewModels?.append(cellViewModel)
}
cellViewModels?.insert(viewModel, at: 0)
}
}
}
func reloadData() {
contentLoader.reset()
loadData(contentLoader)
......
......@@ -11,4 +11,5 @@ import UIKit
public protocol NewsListControllerDelegate: NSObjectProtocol {
func didStartLoading()
func didFinishLoading()
func didLoadFeaturedNews()
}
//
// FeaturedCollectionCellViewModelInterface.swift
// NewsListModule
//
// Created by Sasha Klovak on 6/26/20.
// Copyright © 2020 Triare. All rights reserved.
//
import UIKit
protocol FeaturedNewsCollectionCellViewModelInterface: CollectionCellViewModelInterface, NewsCellViewModelInterface {
}
//
// HorizontalListCollectionCellViewModelInterface.swift
// NewsListModule
//
// Created by Sasha Klovak on 6/25/20.
// Copyright © 2020 Triare. All rights reserved.
//
import UIKit
protocol HorizontalListTableCellViewModelInterface: TableCellViewModelInterface {
var cellViewModels: [CellViewModelInterface]? { get set }
}
......@@ -15,12 +15,14 @@ protocol NewsCellViewModelInterface {
var publishDate: String? { get set }
var sourceName: String? { get set }
var sourceNameLabelWidth: CGFloat? { get set }
var model: NewsModel? { get set }
}
extension NewsCellViewModelInterface {
mutating func update(for model: Any) {
guard let _model = model as? NewsModel else { return }
self.model = _model
title = _model.title
subtitle = _model.description
imageURL = URL(string: _model.urlToImage ?? "")
......
......@@ -20,6 +20,9 @@ protocol NewsListControllerInterface: NSObjectProtocol {
func loadData(_ contentLoader: ContentLoader)
func loadMore(currentIndex: Int)
func reloadData()
func loadFeaturedData()
func prepareFeaturedCellViewModels(_ listModel: NewsListModel?, error: Error?)
func itemsCount() -> Int
}
extension NewsListControllerInterface {
......@@ -35,6 +38,18 @@ extension NewsListControllerInterface {
self?.finishLoading()
}
}
func loadFeaturedData() {
if networkManager == nil {
networkManager = NetworkManager()
}
networkManager?.getFeaturedNews(completion: { [weak self] (model, error) in
self?.prepareFeaturedCellViewModels(model, error: error)
self?.delegate?.didLoadFeaturedNews()
})
}
func itemsCount() -> Int {
return cellViewModels?.count ?? 0
}
}
......@@ -49,6 +49,14 @@ class NewsListViewController: UIViewController {
@objc private func reloadData() {
controller?.reloadData()
}
private func reloadContent() {
if let tableView = controller?.contentView as? UITableView {
tableView.reloadData()
} else if let collectionView = controller?.contentView as? UICollectionView {
collectionView.reloadData()
}
}
}
extension NewsListViewController: NewsListControllerDelegate {
......@@ -59,11 +67,11 @@ extension NewsListViewController: NewsListControllerDelegate {
func didFinishLoading() {
refreshControl.endRefreshing()
if let tableView = controller?.contentView as? UITableView {
tableView.reloadData()
} else if let collectionView = controller?.contentView as? UICollectionView {
collectionView.reloadData()
}
reloadContent()
}
func didLoadFeaturedNews() {
reloadContent()
}
}