Skip to content

Commit

Permalink
Adding support for Unsplash cloud source.
Browse files Browse the repository at this point in the history
Minor code refactoring.
  • Loading branch information
rnine committed Sep 23, 2020
1 parent ce44e3e commit b09131d
Show file tree
Hide file tree
Showing 12 changed files with 245 additions and 50 deletions.
27 changes: 27 additions & 0 deletions Filestack/Public/Enums/CloudProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,35 @@ import Foundation
/// Amazon Drive
case amazonDrive

/// Unsplash
case unsplash

/// Custom Source
case customSource
}

extension CloudProvider {
/// :nodoc:
public var searchBased: Bool {
switch self {
case .unsplash:
return true
default:
return false
}
}

/// :nodoc:
var viewType: CloudSourceViewType? {
switch self {
case .unsplash:
return .grid
default:
return nil
}
}
}

extension CloudProvider {
/// :nodoc:
public var description: String {
Expand All @@ -68,6 +93,8 @@ extension CloudProvider {
return "onedrive"
case .amazonDrive:
return "clouddrive"
case .unsplash:
return "unsplash"
case .customSource:
return "customsource"
}
Expand Down
2 changes: 1 addition & 1 deletion Filestack/Public/Models/Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ private typealias CompletionHandler = (_ response: CloudResponse, _ safariError:
if let safariError = error {
completionBlock(response, safariError)
} else if let url = url, url == self.authCallbackURL {
_ = self.perform(request: request, queue: queue, completionBlock: completionBlock)
self.perform(request: request, queue: queue, completionBlock: completionBlock)
} else {
completionBlock(response, ClientError.authenticationFailed)
}
Expand Down
6 changes: 3 additions & 3 deletions Filestack/Resources/Icons.xcassets/Contents.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"images" : [
{
"filename" : "icon-unsplash.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "[email protected]",
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import UIKit
private extension String {
static let cloudItemReuseIdentifier = "CloudItemCollectionViewCell"
static let activityIndicatorReuseIdentifier = "ActivityIndicatorCollectionViewCell"
static let headerID = "SearchView"
}

class CloudSourceCollectionViewController: UICollectionViewController {
Expand All @@ -31,42 +32,51 @@ class CloudSourceCollectionViewController: UICollectionViewController {
fatalError("Parent must adopt the CloudSourceDataSource protocol.")
}

// Toggle search header on/off.
if !dataSource.source.provider.searchBased {
(collectionViewLayout as? UICollectionViewFlowLayout)?.headerReferenceSize = .zero
}

// Setup refresh control if we have items
if dataSource.items != nil {
setupRefreshControl()
}

}

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

collectionView!.reloadData()

if dataSource.source.provider.searchBased {
focusOnSearchBar()
}
}

override func viewWillDisappear(_ animated: Bool) {
refreshControl?.endRefreshing()

super.viewWillDisappear(animated)
}
}

// MARK: UICollectionViewDataSource
// MARK: - UICollectionViewDataSource Conformance

extension CloudSourceCollectionViewController {
override func numberOfSections(in _: UICollectionView) -> Int {
return 1
}

override func collectionView(_: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch section {
case 0:

if let items = dataSource.items {
return dataSource.nextPageToken == nil ? items.count : items.count + 1
} else {
return 1
}

default:

return 0
}
}
Expand All @@ -84,11 +94,8 @@ class CloudSourceCollectionViewController: UICollectionViewController {

switch cell {
case let cell as ActivityIndicatorCollectionViewCell:

cell.activityIndicator.startAnimating()

case let cell as CloudItemCollectionViewCell:

guard let item = dataSource.items?[safe: UInt(indexPath.row)] else { return cell }

// Configure the cell
Expand Down Expand Up @@ -121,9 +128,7 @@ class CloudSourceCollectionViewController: UICollectionViewController {
}

cell.imageView?.image = cachedImage

default:

break
}

Expand All @@ -148,8 +153,28 @@ class CloudSourceCollectionViewController: UICollectionViewController {
}
}

// MARK: UICollectionViewDelegate
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {

let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind,
withReuseIdentifier: .headerID,
for: indexPath)
return headerView
}

override func collectionView(_ collectionView: UICollectionView, didEndDisplayingSupplementaryView view: UICollectionReusableView, forElementOfKind elementKind: String, at indexPath: IndexPath) {

if view.reuseIdentifier == .headerID {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
guard let subview = view.subviews.first, !subview.isFirstResponder else { return }
subview.becomeFirstResponder()
}
}
}
}

// MARK: - UICollectionViewDelegate Conformance

extension CloudSourceCollectionViewController {
override func collectionView(_: UICollectionView, shouldHighlightItemAt _: IndexPath) -> Bool {
return true
}
Expand All @@ -163,19 +188,47 @@ class CloudSourceCollectionViewController: UICollectionViewController {
return false
}
}
}

// MARK: - Actions
// MARK: - UISearchBarDelegate Conformance

extension CloudSourceCollectionViewController: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
guard let searchTerm = searchBar.text else { return }

dataSource.search(text: searchTerm) {
self.collectionView!.reloadData()
}
}
}

// MARK: - CloudSourceDataSourceConsumer Conformance

extension CloudSourceCollectionViewController: CloudSourceDataSourceConsumer {
func dataSourceReceivedInitialResults(dataSource _: CloudSourceDataSource) {
// Reload collection view's data
collectionView!.reloadData()
// Setup refresh control
setupRefreshControl()
}
}

// MARK: - Actions

extension CloudSourceCollectionViewController {

@IBAction func refresh(_: Any) {
dataSource.refresh {
self.refreshControl?.endRefreshing()
self.collectionView!.reloadData()
}
}
}

// MARK: - Private Functions
// MARK: - Private Functions

fileprivate func setupRefreshControl() {
private extension CloudSourceCollectionViewController {
func setupRefreshControl() {
guard refreshControl == nil else { return }

refreshControl = UIRefreshControl()
Expand All @@ -186,13 +239,13 @@ class CloudSourceCollectionViewController: UICollectionViewController {
collectionView!.alwaysBounceVertical = true
}
}
}

extension CloudSourceCollectionViewController: CloudSourceDataSourceConsumer {
func dataSourceReceivedInitialResults(dataSource _: CloudSourceDataSource) {
// Reload collection view's data
collectionView!.reloadData()
// Setup refresh control
setupRefreshControl()
func focusOnSearchBar() {
let views = collectionView!.visibleSupplementaryViews(ofKind: UICollectionView.elementKindSectionHeader)

if let searchBar = (views.first?.subviews.first as? UISearchBar) {
searchBar.becomeFirstResponder()
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,11 @@ class CloudSourceTabBarController: UITabBarController, CloudSourceDataSource {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

selectedIndex = viewType.rawValue
setupViewtypeButton()
selectedIndex = (source.provider.viewType ?? viewType).rawValue

if source.provider.viewType == nil {
setupViewTypeButton()
}

guard items == nil else { return }

Expand Down Expand Up @@ -236,6 +239,14 @@ class CloudSourceTabBarController: UITabBarController, CloudSourceDataSource {
thumbnailRequests.append(request)
}

func search(text: String, completionHandler: @escaping (() -> Void)) {
guard let escapedText = text.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) else { return }

path = "/\(escapedText)/"

refresh(completionHandler: completionHandler)
}

func navigate(to item: CloudItem) {
let scene = CloudSourceTabBarScene(client: client,
storeOptions: storeOptions,
Expand All @@ -258,7 +269,7 @@ class CloudSourceTabBarController: UITabBarController, CloudSourceDataSource {
return UIImage.fromFilestackBundle(alternateViewtype.iconName)
}

private func setupViewtypeButton() {
private func setupViewTypeButton() {
if toggleViewTypeButton == nil {
toggleViewTypeButton = UIBarButtonItem(image: alternateIcon(), style: .plain, target: self, action: #selector(toggleViewType))
navigationItem.rightBarButtonItems?.append(toggleViewTypeButton!)
Expand Down Expand Up @@ -291,7 +302,7 @@ class CloudSourceTabBarController: UITabBarController, CloudSourceDataSource {
@IBAction func toggleViewType(_: Any) {
viewType = viewType.toggle()
selectedIndex = viewType.rawValue
setupViewtypeButton()
setupViewTypeButton()
// Store view type in user defaults
UserDefaults.standard.set(cloudSourceViewType: viewType)
}
Expand Down
Loading

0 comments on commit b09131d

Please sign in to comment.