Skip to content

Commit

Permalink
Add Footer in searchResults, improve initial screen UI
Browse files Browse the repository at this point in the history
  • Loading branch information
alexookah committed Dec 1, 2020
1 parent f469bfc commit 912b867
Show file tree
Hide file tree
Showing 9 changed files with 256 additions and 68 deletions.
18 changes: 13 additions & 5 deletions Image Multi Search.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
B4F0E1822576B6CF0046BD56 /* .gitignore in Resources */ = {isa = PBXBuildFile; fileRef = B4F0E1812576B6CF0046BD56 /* .gitignore */; };
B4F0E1BB2576F71E0046BD56 /* SectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4F0E1B92576F71E0046BD56 /* SectionHeader.swift */; };
B4F0E1BC2576F71E0046BD56 /* SectionHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = B4F0E1BA2576F71E0046BD56 /* SectionHeader.xib */; };
B4F0E1C32576FF530046BD56 /* SectionFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4F0E1C12576FF530046BD56 /* SectionFooter.swift */; };
B4F0E1C42576FF530046BD56 /* SectionFooter.xib in Resources */ = {isa = PBXBuildFile; fileRef = B4F0E1C22576FF530046BD56 /* SectionFooter.xib */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand Down Expand Up @@ -57,6 +59,8 @@
B4F0E1812576B6CF0046BD56 /* .gitignore */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = .gitignore; sourceTree = "<group>"; };
B4F0E1B92576F71E0046BD56 /* SectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionHeader.swift; sourceTree = "<group>"; };
B4F0E1BA2576F71E0046BD56 /* SectionHeader.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SectionHeader.xib; sourceTree = "<group>"; };
B4F0E1C12576FF530046BD56 /* SectionFooter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionFooter.swift; sourceTree = "<group>"; };
B4F0E1C22576FF530046BD56 /* SectionFooter.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SectionFooter.xib; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -148,7 +152,7 @@
B4D5FE7625728D800057C141 /* Views */ = {
isa = PBXGroup;
children = (
B4F0E1A12576EC250046BD56 /* KeywordsManager */,
B4F0E1A12576EC250046BD56 /* KeywordsManagerVC */,
B4F0E1A22576EC3B0046BD56 /* SearchResultsVC */,
);
path = Views;
Expand All @@ -162,21 +166,23 @@
path = ViewModel;
sourceTree = "<group>";
};
B4F0E1A12576EC250046BD56 /* KeywordsManager */ = {
B4F0E1A12576EC250046BD56 /* KeywordsManagerVC */ = {
isa = PBXGroup;
children = (
B4D6C88725741C8F00DAEFC1 /* KeywordCell.swift */,
);
path = KeywordsManager;
path = KeywordsManagerVC;
sourceTree = "<group>";
};
B4F0E1A22576EC3B0046BD56 /* SearchResultsVC */ = {
isa = PBXGroup;
children = (
B4D5FE7A2572CAC90057C141 /* PreviewImageSearchCell.xib */,
B4D5FE792572CAC90057C141 /* PreviewImageSearchCell.swift */,
B4F0E1BA2576F71E0046BD56 /* SectionHeader.xib */,
B4F0E1B92576F71E0046BD56 /* SectionHeader.swift */,
B4D5FE7A2572CAC90057C141 /* PreviewImageSearchCell.xib */,
B4D5FE792572CAC90057C141 /* PreviewImageSearchCell.swift */,
B4F0E1C22576FF530046BD56 /* SectionFooter.xib */,
B4F0E1C12576FF530046BD56 /* SectionFooter.swift */,
);
path = SearchResultsVC;
sourceTree = "<group>";
Expand Down Expand Up @@ -246,6 +252,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B4F0E1C42576FF530046BD56 /* SectionFooter.xib in Resources */,
B4A78469257026BC007CBB78 /* LaunchScreen.storyboard in Resources */,
B4A78466257026BC007CBB78 /* Assets.xcassets in Resources */,
B4D5FE7C2572CAC90057C141 /* PreviewImageSearchCell.xib in Resources */,
Expand Down Expand Up @@ -302,6 +309,7 @@
files = (
B4D5FE8A2572D3440057C141 /* ResultItem.swift in Sources */,
B4DF836125751FA100BDF6EC /* Keyword.swift in Sources */,
B4F0E1C32576FF530046BD56 /* SectionFooter.swift in Sources */,
B404C04B257038B2008B76FE /* APIService.swift in Sources */,
B4D5FE9A2572E7C70057C141 /* SearchResultsVC.swift in Sources */,
B404C05325704B42008B76FE /* URLSession.swift in Sources */,
Expand Down
Binary file not shown.
139 changes: 114 additions & 25 deletions Image Multi Search/Base.lproj/Main.storyboard

Large diffs are not rendered by default.

89 changes: 56 additions & 33 deletions Image Multi Search/Controllers/SearchResultsVC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,56 @@ class SearchResultsVC: UIViewController {
collectionView.register(PreviewImageSearchCell.nib(),
forCellWithReuseIdentifier: PreviewImageSearchCell.reuseIdentifier)

collectionView.register(SectionFooter.nib(),
forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter,
withReuseIdentifier: SectionFooter.reuseIdentifier)

createDataSource()
createSections()
createHeaderAndFooter()
// createFooter()

loadData()
}

func createDataSource() {
dataSource = UICollectionViewDiffableDataSource
<Keyword, ResultItem>(collectionView: collectionView) { collectionView, indexPath, searchResult in

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PreviewImageSearchCell.reuseIdentifier,
for: indexPath) as? PreviewImageSearchCell
cell?.configWith(resultItem: searchResult)
return cell
}
}

func createHeaderAndFooter() {
dataSource?.supplementaryViewProvider = { [weak self] collectionView, kind, indexPath in
if kind == UICollectionView.elementKindSectionHeader {
guard let header = collectionView
.dequeueReusableSupplementaryView(ofKind: kind,
withReuseIdentifier: SectionHeader.reuseIdentifier,
for: indexPath) as? SectionHeader else { return nil }

guard
let firstKeyword = self?.dataSource?.itemIdentifier(for: indexPath),
let keyword = self?.dataSource?.snapshot().sectionIdentifier(containingItem: firstKeyword),
let searchResult = keyword.searchResult, searchResult.items.count > 0
else { return header }

header.configWith(keyword: keyword)
return header
} else {
guard let footer = collectionView
.dequeueReusableSupplementaryView(ofKind: kind,
withReuseIdentifier: SectionFooter.reuseIdentifier,
for: indexPath) as? SectionFooter
else { return nil }

return footer
}
}
}

func loadData() {

var snapshot = NSDiffableDataSourceSnapshot<Keyword, ResultItem>()
Expand All @@ -49,37 +93,6 @@ class SearchResultsVC: UIViewController {
dataSource?.apply(snapshot)
}

func createSections() {
dataSource?.supplementaryViewProvider = { [weak self] collectionView, kind, indexPath in
guard let sectionHeader = collectionView
.dequeueReusableSupplementaryView(ofKind: kind,
withReuseIdentifier: SectionHeader.reuseIdentifier,
for: indexPath) as? SectionHeader
else { return nil }

guard
let firstKeyword = self?.dataSource?.itemIdentifier(for: indexPath),
let keyword = self?.dataSource?.snapshot().sectionIdentifier(containingItem: firstKeyword),
let searchResult = keyword.searchResult, searchResult.items.count > 0
else { return sectionHeader }

sectionHeader.title.text = searchResult.sectionTitle?.uppercased()
sectionHeader.subtitle.text = "total results: " + searchResult.searchInformation.formattedTotalResults
return sectionHeader
}
}

func createDataSource() {
dataSource = UICollectionViewDiffableDataSource
<Keyword, ResultItem>(collectionView: collectionView) { collectionView, indexPath, searchResult in

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PreviewImageSearchCell.reuseIdentifier,
for: indexPath) as? PreviewImageSearchCell
cell?.configWith(resultItem: searchResult)
return cell
}
}

func createCompositionalLayout() -> UICollectionViewLayout {
let layout = UICollectionViewCompositionalLayout { sectionIndex, _ in
guard let searchResultItems = self.keywordsViewModel.keywords[sectionIndex].searchResult?.items,
Expand Down Expand Up @@ -108,7 +121,8 @@ class SearchResultsVC: UIViewController {
layoutSection.orthogonalScrollingBehavior = .groupPagingCentered

let layoutSectionHeader = createSectionHeaderLayout()
layoutSection.boundarySupplementaryItems = [layoutSectionHeader]
let layoutSectionFooter = createSectionFooterLayout()
layoutSection.boundarySupplementaryItems = [layoutSectionHeader, layoutSectionFooter]

return layoutSection
}
Expand All @@ -122,6 +136,15 @@ class SearchResultsVC: UIViewController {
return layout
}

func createSectionFooterLayout() -> NSCollectionLayoutBoundarySupplementaryItem {
let layoutSectionHeaderSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.93),
heightDimension: .estimated(40))
let layout = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: layoutSectionHeaderSize,
elementKind: UICollectionView.elementKindSectionFooter,
alignment: .bottom)
return layout
}

}

// MARK: UICollectionViewDataSourcePrefetching
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ class KeywordCell: UITableViewCell {
self.setStatusImage(systemName: "ellipsis")
case .success:
self.setStatusImage(systemName: "checkmark.circle")
case .failed:
self.setStatusImage(systemName: "exclamationmark.triangle")
case .noItems:
self.setStatusImage(systemName: "xmark.circle")
case .failed:
self.setStatusImage(systemName: "exclamationmark.triangle")
}
}
.store(in: &cancellables)
Expand Down
22 changes: 22 additions & 0 deletions Image Multi Search/Views/SearchResultsVC/SectionFooter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// SectionFooter.swift
// Image Multi Search
//
// Created by Alexandros Lykesas on 2/12/20.
//

import UIKit

class SectionFooter: UICollectionReusableView {

static let reuseIdentifier = "SectionFooter"

override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}

static func nib() -> UINib {
return UINib(nibName: reuseIdentifier, bundle: nil)
}
}
40 changes: 40 additions & 0 deletions Image Multi Search/Views/SearchResultsVC/SectionFooter.xib
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17505"/>
<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"/>
<collectionReusableView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="SectionFooter" id="U6b-Vx-4bR" customClass="SectionFooter" customModule="Image_Multi_Search" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="320" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="a0g-6i-mM0">
<rect key="frame" x="172" y="6.5" width="132" height="37"/>
<color key="backgroundColor" red="0.0" green="0.36397528649999999" blue="0.55531209709999996" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<inset key="contentEdgeInsets" minX="24" minY="8" maxX="24" maxY="8"/>
<state key="normal" title="View more">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="8"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</button>
</subviews>
<viewLayoutGuide key="safeArea" id="VXr-Tz-HHm"/>
<constraints>
<constraint firstItem="a0g-6i-mM0" firstAttribute="centerY" secondItem="U6b-Vx-4bR" secondAttribute="centerY" id="Ans-7y-an3"/>
<constraint firstAttribute="trailing" secondItem="a0g-6i-mM0" secondAttribute="trailing" constant="16" id="LKJ-S0-mY0"/>
</constraints>
<point key="canvasLocation" x="-146" y="113"/>
</collectionReusableView>
</objects>
</document>
4 changes: 2 additions & 2 deletions Image Multi Search/Views/SearchResultsVC/SectionHeader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ class SectionHeader: UICollectionReusableView {
@IBOutlet weak var title: UILabel!
@IBOutlet weak var subtitle: UILabel!

func configWithKeyword(keyword: Keyword) {
title.text = keyword.searchResult?.sectionTitle
func configWith(keyword: Keyword) {
title.text = keyword.searchResult?.sectionTitle?.uppercased()
let totalResults = keyword.searchResult?.searchInformation.formattedTotalResults

if let totalResults = totalResults {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict/>
<dict>
<key>B4A78458257026BB007CBB78</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>

0 comments on commit 912b867

Please sign in to comment.