Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

[NT-644] See all project category fix #1061

Merged
merged 11 commits into from
Feb 13, 2020
4 changes: 0 additions & 4 deletions Kickstarter-iOS/DataSources/ThanksProjectsDataSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,4 @@ internal final class ThanksProjectsDataSource: ValueCellDataSource {

return discoveryProjectCellRowValue?.project
}

internal func categoryAtIndexPath(_ indexPath: IndexPath) -> KsApi.Category? {
return self[indexPath] as? KsApi.Category
}
}
13 changes: 4 additions & 9 deletions Kickstarter-iOS/DataSources/ThanksProjectsDataSourceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,9 @@ final class ThanksProjectsDataSourceTests: XCTestCase {
]
dataSource.loadData(projects: projects, category: Category.games)

let indexPath0 = IndexPath(item: 0, section: 0)
let indexPath1 = IndexPath(item: 1, section: 0)
let indexPath2 = IndexPath(item: 2, section: 0)
let indexPath3 = IndexPath(item: 3, section: 0)

XCTAssertNil(dataSource.categoryAtIndexPath(indexPath0), "Category is nil for non-category item")
XCTAssertNil(self.dataSource.categoryAtIndexPath(indexPath1), "Category is nil for non-category item")
XCTAssertNil(self.dataSource.categoryAtIndexPath(indexPath2), "Category is nil for non-category item")
XCTAssertEqual(Category.games, self.dataSource.categoryAtIndexPath(indexPath3))
XCTAssertEqual("DiscoveryPostcardCell", self.dataSource.reusableId(item: 0, section: 0))
XCTAssertEqual("DiscoveryPostcardCell", self.dataSource.reusableId(item: 1, section: 0))
XCTAssertEqual("DiscoveryPostcardCell", self.dataSource.reusableId(item: 2, section: 0))
XCTAssertEqual("ThanksCategoryCell", self.dataSource.reusableId(item: 3, section: 0))
}
}
38 changes: 36 additions & 2 deletions Kickstarter-iOS/Views/Cells/ThanksCategoryCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,48 @@ import Library
import Prelude
import UIKit

internal protocol ThanksCategoryCellDelegate: AnyObject {
func thanksCategoryCell(_ cell: ThanksCategoryCell, didTapSeeAllProjectsWith category: KsApi.Category)
}

internal final class ThanksCategoryCell: UITableViewCell, ValueCell {
internal weak var delegate: ThanksCategoryCellDelegate?
fileprivate let viewModel: ThanksCategoryCellViewModelType = ThanksCategoryCellViewModel()

@IBOutlet fileprivate var seeAllProjectsButton: UIButton!

override func awakeFromNib() {
super.awakeFromNib()

self.seeAllProjectsButton
.addTarget(self, action: #selector(self.seeAllProjectsButtonTapped), for: .touchUpInside)
}

func configureWith(value category: KsApi.Category) {
self.viewModel.inputs.configureWith(category: category)
}

internal override func bindStyles() {
super.bindStyles()

_ = self.seeAllProjectsButton
|> greyButtonStyle
|> UIButton.lens.title(for: .normal) %~ {
_ in Strings.See_all_category_name_projects(category_name: category.name)
}

internal override func bindViewModel() {
super.bindViewModel()

self.viewModel.outputs.notifyDelegateToGoToDiscovery
.observeForControllerAction()
.observeValues { [weak self] in
guard let self = self else { return }
self.delegate?.thanksCategoryCell(self, didTapSeeAllProjectsWith: $0)
}

self.seeAllProjectsButton.rac.title = self.viewModel.outputs.seeAllProjectCategoryTitle
}

@objc fileprivate func seeAllProjectsButtonTapped() {
self.viewModel.inputs.seeAllProjectsButtonTapped()
}
}
17 changes: 15 additions & 2 deletions Kickstarter-iOS/Views/Controllers/ThanksViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -257,14 +257,21 @@ internal final class ThanksViewController: UIViewController, UITableViewDelegate
self.present(controller, animated: true, completion: nil)
}

internal func tableView(
_: UITableView, willDisplay cell: UITableViewCell,
forRowAt _: IndexPath
) {
if let cell = cell as? ThanksCategoryCell {
cell.delegate = self
}
}

internal func tableView(
_: UITableView,
didSelectRowAt indexPath: IndexPath
) {
if let project = self.dataSource.projectAtIndexPath(indexPath) {
self.viewModel.inputs.projectTapped(project)
} else if let category = self.dataSource.categoryAtIndexPath(indexPath) {
self.viewModel.inputs.categoryCellTapped(category)
}
}

Expand All @@ -280,3 +287,9 @@ internal final class ThanksViewController: UIViewController, UITableViewDelegate
extension ThanksViewController: ProjectNavigatorDelegate {
func transitionedToProject(at _: Int) {}
}

extension ThanksViewController: ThanksCategoryCellDelegate {
func thanksCategoryCell(_: ThanksCategoryCell, didTapSeeAllProjectsWith category: KsApi.Category) {
self.viewModel.inputs.categoryCellTapped(category)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is an existing input but could also be good to align this naming with the delegate method naming once that's updated πŸ€·β€β™‚

}
}
2 changes: 1 addition & 1 deletion Kickstarter-iOS/Views/Storyboards/ThanksCategoryCell.xib
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<edgeInsets key="layoutMargins" top="16" left="16" bottom="16" right="16"/>
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
<connections>
<outlet property="seeAllProjectsButton" destination="hbb-GW-PrV" id="Sfl-8U-s0p"/>
<outlet property="seeAllProjectsButton" destination="hbb-GW-PrV" id="yk8-KW-44G"/>
</connections>
<point key="canvasLocation" x="-133" y="-727"/>
</tableViewCell>
Expand Down
8 changes: 8 additions & 0 deletions Kickstarter.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,8 @@
D796868021013C1F00E54C61 /* SettingsPrivacyStaticCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D796867F21013C1F00E54C61 /* SettingsPrivacyStaticCell.swift */; };
D798A6AE21656D970053D097 /* Currency.swift in Sources */ = {isa = PBXBuildFile; fileRef = D798A6AD21656D970053D097 /* Currency.swift */; };
D798A748216698CE0053D097 /* SettingsAccountViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D798A70F216695090053D097 /* SettingsAccountViewModelTests.swift */; };
D79970B423EB79A600584911 /* ThanksCategoryCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D79970B223EB6FF800584911 /* ThanksCategoryCellViewModel.swift */; };
D79970B723EC88CB00584911 /* ThanksCategoryCellViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D79970B523EC88BB00584911 /* ThanksCategoryCellViewModelTests.swift */; };
D79A01A42242E8CD004BC6A8 /* AppEnvironmentType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D764373F22414FA900DAFC9E /* AppEnvironmentType.swift */; };
D79A01A52242E91E004BC6A8 /* PushNotificationDialogType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76437782241500600DAFC9E /* PushNotificationDialogType.swift */; };
D79A0583225E9B7B004BC6A8 /* PledgeDescriptionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D79A054A225E9B6B004BC6A8 /* PledgeDescriptionViewController.swift */; };
Expand Down Expand Up @@ -2576,6 +2578,8 @@
D796867F21013C1F00E54C61 /* SettingsPrivacyStaticCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsPrivacyStaticCell.swift; sourceTree = "<group>"; };
D798A6AD21656D970053D097 /* Currency.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Currency.swift; sourceTree = "<group>"; };
D798A70F216695090053D097 /* SettingsAccountViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAccountViewModelTests.swift; sourceTree = "<group>"; };
D79970B223EB6FF800584911 /* ThanksCategoryCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThanksCategoryCellViewModel.swift; sourceTree = "<group>"; };
D79970B523EC88BB00584911 /* ThanksCategoryCellViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThanksCategoryCellViewModelTests.swift; sourceTree = "<group>"; };
D79A054A225E9B6B004BC6A8 /* PledgeDescriptionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PledgeDescriptionViewController.swift; sourceTree = "<group>"; };
D79CF2F2219CC91000ECB73A /* AddNewCardViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddNewCardViewModel.swift; sourceTree = "<group>"; };
D79CF32B219CDEE100ECB73A /* CreatePaymentsSourceMutation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatePaymentsSourceMutation.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3803,6 +3807,8 @@
D723708B2118CAD8001EA4CA /* SettingsDeleteAccountCellViewModelTests.swift */,
D796867B20FE655300E54C61 /* SettingsFollowCellViewModel.swift */,
D7237095211A1593001EA4CA /* SettingsFollowCellViewModelTests.swift */,
D79970B223EB6FF800584911 /* ThanksCategoryCellViewModel.swift */,
D79970B523EC88BB00584911 /* ThanksCategoryCellViewModelTests.swift */,
D6B6766420FE85000082717D /* SettingsNewslettersCellViewModel.swift */,
D6B4EFFF21079F750079159D /* SettingsNewslettersCellViewModelTests.swift */,
D6B4EFC5210686270079159D /* SettingsNewslettersViewModel.swift */,
Expand Down Expand Up @@ -4830,6 +4836,7 @@
8A213CEF239EAEA400BBB4C7 /* Koala.swift in Sources */,
D70347901DBAABC30099C668 /* DiscoveryExpandableRowCellViewModel.swift in Sources */,
0199545F1D2D818E00BC1390 /* DashboardProjectsDrawerViewModel.swift in Sources */,
D79970B423EB79A600584911 /* ThanksCategoryCellViewModel.swift in Sources */,
D67DF564232ABB960051D207 /* ManagePledgeViewModel.swift in Sources */,
D0A787BF2204D975006AE4F4 /* UITableView+AutoLayoutHeaderView.swift in Sources */,
A76126B91C90C94000EDCCB9 /* UIView-Extensions.swift in Sources */,
Expand Down Expand Up @@ -5059,6 +5066,7 @@
778F891E22D5414F00D095C5 /* Feature+HelpersTests.swift in Sources */,
A7ED1F2C1E830FDC00BFFA01 /* KSCacheTests.swift in Sources */,
D7237096211A1593001EA4CA /* SettingsFollowCellViewModelTests.swift in Sources */,
D79970B723EC88CB00584911 /* ThanksCategoryCellViewModelTests.swift in Sources */,
8A8099F522E2143000373E66 /* RewardCardContainerViewModelTests.swift in Sources */,
774D98DE23B1613800FC81C2 /* MockOptimizelyClient.swift in Sources */,
D667C2BC2305F03300EC094A /* ExperimentName+HelpersTests.swift in Sources */,
Expand Down
50 changes: 50 additions & 0 deletions Library/ViewModels/ThanksCategoryCellViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import Foundation
import KsApi
import Prelude
import ReactiveExtensions
import ReactiveSwift

public protocol ThanksCategoryCellViewModelInputs {
func seeAllProjectsButtonTapped()
func configureWith(category: KsApi.Category)
}

public protocol ThanksCategoryCellViewModelOutputs {
var notifyDelegateToGoToDiscovery: Signal<KsApi.Category, Never> { get }
var seeAllProjectCategoryTitle: Signal<String, Never> { get }
}

public protocol ThanksCategoryCellViewModelType {
var inputs: ThanksCategoryCellViewModelInputs { get }
var outputs: ThanksCategoryCellViewModelOutputs { get }
}

public final class ThanksCategoryCellViewModel: ThanksCategoryCellViewModelType,
ThanksCategoryCellViewModelInputs, ThanksCategoryCellViewModelOutputs {
public init() {
let projectCategory = self.categoryProperty.signal.skipNil()

self.seeAllProjectCategoryTitle = projectCategory.map {
Strings.See_all_category_name_projects(category_name: $0.name)
}

self.notifyDelegateToGoToDiscovery = projectCategory
.takeWhen(self.seeAllProjectsButtonTappedProperty.signal)
}

fileprivate let categoryProperty = MutableProperty<KsApi.Category?>(nil)
public func configureWith(category: KsApi.Category) {
self.categoryProperty.value = category
}

fileprivate let seeAllProjectsButtonTappedProperty = MutableProperty(())
public func seeAllProjectsButtonTapped() {
self.seeAllProjectsButtonTappedProperty.value = ()
}

public let seeAllProjectCategoryTitle: Signal<String, Never>
public let notifyDelegateToGoToDiscovery: Signal<KsApi.Category, Never>

public var inputs: ThanksCategoryCellViewModelInputs { return self }
public var outputs: ThanksCategoryCellViewModelOutputs { return self }
}
35 changes: 35 additions & 0 deletions Library/ViewModels/ThanksCategoryCellViewModelTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@testable import KsApi
import Library
import Prelude
import ReactiveExtensions_TestHelpers
import XCTest

final class ThanksCategoryCellViewModelTests: TestCase {
private let notifyDelegateToGoToDiscovery = TestObserver<KsApi.Category, Never>()
private let seeAllProjectCategoryTitle = TestObserver<String, Never>()
private let vm = ThanksCategoryCellViewModel()

override func setUp() {
super.setUp()

self.vm.notifyDelegateToGoToDiscovery.observe(self.notifyDelegateToGoToDiscovery.observer)
self.vm.seeAllProjectCategoryTitle.observe(self.seeAllProjectCategoryTitle.observer)
}

func testNotifyDelegate() {
let category = Category.template

self.vm.inputs.configureWith(category: category)
self.notifyDelegateToGoToDiscovery.assertDidNotEmitValue()
self.vm.inputs.seeAllProjectsButtonTapped()
self.notifyDelegateToGoToDiscovery.assertDidEmitValue()
}

func testSeeAllProjectCategoryButtonTitle() {
let category = Category.template
|> Category.lens.name .~ "Art"

self.vm.inputs.configureWith(category: category)
self.seeAllProjectCategoryTitle.assertValues(["See all Art projects"])
}
}
4 changes: 3 additions & 1 deletion Library/ViewModels/ThanksViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,9 @@ public final class ThanksViewModel: ThanksViewModelType, ThanksViewModelInputs,
.mapConst(Notification(name: .ksr_projectBacked))

self.goToDiscovery = self.categoryCellTappedProperty.signal.skipNil()
.map { DiscoveryParams.defaults |> DiscoveryParams.lens.category .~ $0 }
.map {
DiscoveryParams.defaults |> DiscoveryParams.lens.category .~ $0
}

let rootCategory: Signal<KsApi.Category, Never> = project
.map { toBase64($0.category) }
Expand Down