Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[MBL-902] [MBL-934] [MBL-928] Use of AI Screen, Analytics, Question Headers, Translations #1843

Merged
merged 27 commits into from
Aug 22, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
bfde6bc
Updated model with ai disclosure fields
msadoon Aug 2, 2023
bb2c048
added use of ai tab
msadoon Aug 8, 2023
32dd553
Merge branch 'main' into mbl-900/new-tab-use-of-ai
msadoon Aug 9, 2023
b879f74
Merge branch 'main' into mbl-900/new-tab-use-of-ai
msadoon Aug 9, 2023
f913b88
fixed a test for use of ai tab title
msadoon Aug 9, 2023
e32af42
Merge branch 'mbl-900/new-tab-use-of-ai' of https://github.com/kickst…
msadoon Aug 9, 2023
ad87197
formatting
msadoon Aug 9, 2023
f10b5dd
updated all cells for use of ai tab except the funding ones. Up next.
msadoon Aug 9, 2023
aafa8a2
added final cell and tested - pretty close to design, one padding iss…
msadoon Aug 10, 2023
7bb8164
Merge branch 'main' into mbl-902/use-of-ai-screen
msadoon Aug 15, 2023
590d75f
Stop using stack view in order to align checkmark and label
ifosli Aug 15, 2023
0d66016
Update footer to link to AI policy
ifosli Aug 16, 2023
fecc868
Update link to have plain text default
ifosli Aug 17, 2023
06b15b2
Merge branch 'main' into mbl-902/use-of-ai-screen
msadoon Aug 21, 2023
de7f8b2
Use translatable strings
ifosli Aug 21, 2023
b84815b
added analytics, checking if involves ai is true along with the exist…
msadoon Aug 21, 2023
90764de
Merge branch 'mbl-902/use-of-ai-screen' of https://github.com/kicksta…
msadoon Aug 21, 2023
15e8a20
Add a11y label so voiceover reads tab correctly
ifosli Aug 22, 2023
84b77b1
Added titles to questions and answers, all sections should be accurat…
msadoon Aug 22, 2023
55736ad
Merge branch 'mbl-902/use-of-ai-screen' of https://github.com/kicksta…
msadoon Aug 22, 2023
c433f53
correct to title headers and order
msadoon Aug 22, 2023
2b17624
tested kickstarter-ios and library
msadoon Aug 22, 2023
2a0559f
ksapi changes tested
msadoon Aug 22, 2023
f657b3c
Merge branch 'main' into mbl-902/use-of-ai-screen
msadoon Aug 22, 2023
923813b
pr comments
msadoon Aug 22, 2023
9cfd437
Merge branch 'mbl-902/use-of-ai-screen' of https://github.com/kicksta…
msadoon Aug 22, 2023
7973635
removing cell separator and added a FIXME for title cell
msadoon Aug 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,9 @@ public final class ProjectPageViewController: UIViewController, MessageBannerVie
self.tableView.registerCellClass(ProjectFAQsAskAQuestionCell.self)
self.tableView.registerCellClass(ProjectFAQsCell.self)
self.tableView.registerCellClass(ProjectFAQsEmptyStateCell.self)
self.tableView.registerCellClass(ProjectEnvironmentalCommitmentCell.self)
self.tableView.registerCellClass(ProjectEnvironmentalCommitmentDisclaimerCell.self)
self.tableView.registerCellClass(ProjectTabCategoryDescriptionCell.self)
self.tableView.registerCellClass(ProjectTabDisclaimerCell.self)
self.tableView.registerCellClass(ProjectTabCheckmarkListCell.self)
self.tableView.registerCellClass(ProjectHeaderCell.self)
self.tableView.registerCellClass(ProjectPamphletCreatorHeaderCell.self)
self.tableView.registerCellClass(TextViewElementCell.self)
Expand Down Expand Up @@ -821,7 +822,7 @@ extension ProjectPageViewController: UITableViewDelegate {
}

public func tableView(_: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if let cell = cell as? ProjectEnvironmentalCommitmentDisclaimerCell, cell.delegate == nil {
if let cell = cell as? ProjectTabDisclaimerCell, cell.delegate == nil {
cell.delegate = self
} else if let cell = cell as? ProjectRisksDisclaimerCell, cell.delegate == nil {
cell.delegate = self
Expand Down Expand Up @@ -902,14 +903,14 @@ extension ProjectPageViewController: MessageDialogViewControllerDelegate {
internal func messageDialog(_: MessageDialogViewController, postedMessage _: Message) {}
}

// MARK: - ProjectEnvironmentalCommitmentDisclaimerCellDelegate
// MARK: - ProjectTabDisclaimerCellDelegate

extension ProjectPageViewController: ProjectEnvironmentalCommitmentDisclaimerCellDelegate {
func projectEnvironmentalCommitmentDisclaimerCell(
_: ProjectEnvironmentalCommitmentDisclaimerCell,
extension ProjectPageViewController: ProjectTabDisclaimerCellDelegate {
func projectTabDisclaimerCell(
_: ProjectTabDisclaimerCell,
didTapURL: URL
) {
self.viewModel.inputs.projectEnvironmentalCommitmentDisclaimerCellDidTapURL(didTapURL)
self.viewModel.inputs.projectTabDisclaimerCellDidTapURL(didTapURL)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import XCTest
internal final class ProjectPageViewControllerTests: TestCase {
private var project: Project = .cosmicSurgery
private let extendedProjectProperties = ExtendedProjectProperties(
environmentalCommitments: [ProjectEnvironmentalCommitment(
environmentalCommitments: [ProjectTabCategoryDescription(
description: "Environmental Commitment",
category: .environmentallyFriendlyFactories,
id: 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ internal final class ProjectPageViewControllerDataSource: ValueCellDataSource {
case risksHeader
case risks
case risksDisclaimer
case aiDisclosureHeader
case aiDisclosureFunding
case aiDisclosureGenerated
case aiDisclosureOtherDetails
case aiDisclosureDisclaimer
case environmentalCommitmentsHeader
case environmentalCommitments
case environmentalCommitmentsDisclaimer
Expand All @@ -29,6 +34,7 @@ internal final class ProjectPageViewControllerDataSource: ValueCellDataSource {
case environmentalCommitments
case faqs
case risks
case aiDisclosure

var description: String {
switch self {
Expand All @@ -42,6 +48,8 @@ internal final class ProjectPageViewControllerDataSource: ValueCellDataSource {
return Strings.Frequently_asked_questions()
case .risks:
return Strings.Risks_and_challenges()
case .aiDisclosure:
return "Use of AI"
}
}
}
Expand Down Expand Up @@ -207,8 +215,52 @@ internal final class ProjectPageViewControllerDataSource: ValueCellDataSource {
inSection: Section.risksDisclaimer.rawValue
)
case .aiDisclosure:
// TODO: Doing in: https://kickstarter.atlassian.net/browse/MBL-902
_ = {}
self.set(
values: [HeaderValue.aiDisclosure.description],
cellClass: ProjectHeaderCell.self,
inSection: Section.aiDisclosureHeader.rawValue
)

guard let aiDisclosure = project.extendedProjectProperties?.aiDisclosure else {
self.set(
values: [.environmental],
cellClass: ProjectTabDisclaimerCell.self,
inSection: Section.environmentalCommitmentsDisclaimer.rawValue
)

return
}

if aiDisclosure.funding.fundingForAiAttribution || aiDisclosure.funding
.fundingForAiConsent || aiDisclosure.funding.fundingForAiOption {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should be checking that .involvesFunding is true here, in addition to this check.

self.set(
values: [aiDisclosure.funding],
cellClass: ProjectTabCheckmarkListCell.self,
inSection: Section.aiDisclosureFunding.rawValue
)
}

if let consentAndDetailAIDetailValues = aiDisclosure.generatedByAiConsentAndDetails {
self.set(
values: [consentAndDetailAIDetailValues],
cellClass: ProjectTabCategoryDescriptionCell.self,
inSection: Section.aiDisclosureGenerated.rawValue
)
}

if let otherAIDetailValues = aiDisclosure.otherAiDetails {
Copy link
Contributor

Choose a reason for hiding this comment

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

And here we should also check that .involvesOther is true

self.set(
values: [otherAIDetailValues],
cellClass: ProjectTabCategoryDescriptionCell.self,
inSection: Section.aiDisclosureOtherDetails.rawValue
)
}

self.set(
values: [.aiDisclosure],
cellClass: ProjectTabDisclaimerCell.self,
inSection: Section.environmentalCommitmentsDisclaimer.rawValue
)
case .environmentalCommitments:
let environmentalCommitments = project.extendedProjectProperties?.environmentalCommitments ?? []

Expand All @@ -220,24 +272,26 @@ internal final class ProjectPageViewControllerDataSource: ValueCellDataSource {

self.set(
values: environmentalCommitments,
cellClass: ProjectEnvironmentalCommitmentCell.self,
cellClass: ProjectTabCategoryDescriptionCell.self,
inSection: Section.environmentalCommitments.rawValue
)

self.set(
values: [()],
cellClass: ProjectEnvironmentalCommitmentDisclaimerCell.self,
values: [.environmental],
cellClass: ProjectTabDisclaimerCell.self,
inSection: Section.environmentalCommitmentsDisclaimer.rawValue
)
}
}

override func configureCell(tableCell cell: UITableViewCell, withValue value: Any) {
switch (cell, value) {
case let (cell as ProjectEnvironmentalCommitmentCell, value as ProjectEnvironmentalCommitment):
case let (cell as ProjectTabCategoryDescriptionCell, value as ProjectTabCategoryDescription):
cell.configureWith(value: value)
case let (cell as ProjectTabCheckmarkListCell, value as ProjectTabFundingOptions):
cell.configureWith(value: value)
case let (cell as ProjectTabDisclaimerCell, value as ProjectDisclaimerType):
cell.configureWith(value: value)
case let (cell as ProjectEnvironmentalCommitmentDisclaimerCell, _):
cell.configureWith(value: ())
case let (cell as ProjectHeaderCell, value as String):
cell.configureWith(value: value)
case let (cell as ProjectFAQsAskAQuestionCell, _):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@ final class ProjectPageViewControllerDataSourceTests: XCTestCase {

private let expectedTime = CMTime(seconds: 123.4, preferredTimescale: CMTimeScale(1))
private let environmentalCommitments = [
ProjectEnvironmentalCommitment(
ProjectTabCategoryDescription(
description: "foo bar",
category: .environmentallyFriendlyFactories,
id: 0
),
ProjectEnvironmentalCommitment(description: "hello world", category: .longLastingDesign, id: 1),
ProjectEnvironmentalCommitment(
ProjectTabCategoryDescription(description: "hello world", category: .longLastingDesign, id: 1),
ProjectTabCategoryDescription(
description: "Lorem ipsum",
category: .reusabilityAndRecyclability,
id: 2
),
ProjectEnvironmentalCommitment(description: "blah blah blah", category: .sustainableDistribution, id: 3)
ProjectTabCategoryDescription(description: "blah blah blah", category: .sustainableDistribution, id: 3)
]

private let faqs = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import Library
import Prelude
import UIKit

final class ProjectEnvironmentalCommitmentCell: UITableViewCell, ValueCell {
final class ProjectTabCategoryDescriptionCell: UITableViewCell, ValueCell {
// MARK: - Properties

private let viewModel = ProjectEnvironmentalCommitmentCellViewModel()
private let viewModel = ProjectTabCategoryDescriptionCellViewModel()

private lazy var categoryLabel: UILabel = {
UILabel(frame: .zero)
Expand Down Expand Up @@ -72,7 +72,7 @@ final class ProjectEnvironmentalCommitmentCell: UITableViewCell, ValueCell {

// MARK: - Configuration

func configureWith(value: ProjectEnvironmentalCommitment) {
func configureWith(value: ProjectTabCategoryDescription) {
self.viewModel.inputs.configureWith(value: value)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import KsApi
import Library
import Prelude
import UIKit

final class ProjectTabCheckmarkListCell: UITableViewCell, ValueCell {
// MARK: - Properties

private let viewModel = ProjectTabCheckmarkListCellViewModel()

private lazy var categoryLabel: UILabel = {
UILabel(frame: .zero)
|> \.translatesAutoresizingMaskIntoConstraints .~ false
}()

private lazy var fundingStackView: UIStackView = {
UIStackView(frame: .zero)
|> \.translatesAutoresizingMaskIntoConstraints .~ false
}()

private lazy var rootStackView = {
UIStackView(frame: .zero)
|> \.translatesAutoresizingMaskIntoConstraints .~ false
}()

// MARK: - Lifecycle

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)

self.bindStyles()
self.configureViews()
self.bindViewModel()
}

required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

// MARK: - Bindings

override func bindViewModel() {
super.bindViewModel()

self.categoryLabel.rac.text = self.viewModel.outputs.categoryLabelText

self.viewModel.outputs.descriptionOptionsText
.observeForUI()
.observeValues { [weak self] options in
self?.fundingStackView.arrangedSubviews.forEach { $0.removeFromSuperview() }

_ = options.map { [weak self] optionText in
let imageLabelView = UIView(frame: .zero)

let label = UILabel(frame: .zero)
|> \.text .~ optionText
|> optionTextLabelStyle

let icon = UIImageView(frame: .zero)
|> iconImageStyle

imageLabelView.addSubview(icon)
imageLabelView.addSubview(label)

NSLayoutConstraint.activate([
msadoon marked this conversation as resolved.
Show resolved Hide resolved
icon.leadingAnchor.constraint(equalTo: imageLabelView.leadingAnchor),
icon.topAnchor.constraint(equalTo: imageLabelView.topAnchor, constant: Styles.grid(1)),
label.leadingAnchor.constraint(equalTo: icon.trailingAnchor, constant: Styles.grid(2)),
label.topAnchor.constraint(equalTo: imageLabelView.topAnchor),
label.trailingAnchor.constraint(equalTo: imageLabelView.trailingAnchor),
label.bottomAnchor.constraint(equalTo: imageLabelView.bottomAnchor)
])

self?.fundingStackView.addArrangedSubview(imageLabelView)
}

self?.fundingStackView.setNeedsDisplay()
}
}

override func bindStyles() {
super.bindStyles()

_ = self
|> baseTableViewCellStyle()
|> \.separatorInset .~ .init(leftRight: Styles.projectPageLeftRightInset)

_ = self.contentView
|> \.layoutMargins .~
.init(
topBottom: Styles.grid(2),
leftRight: Styles.projectPageLeftRightInset
)

_ = self.categoryLabel
|> categoryLabelStyle

_ = self.rootStackView
|> rootStackViewStyle

_ = self.fundingStackView
|> fundingStackViewStyle
}

// MARK: - Configuration

func configureWith(value: ProjectTabFundingOptions) {
self.viewModel.inputs.configureWith(value: value)
}

private func configureViews() {
_ = (self.rootStackView, self.contentView)
|> ksr_addSubviewToParent()
|> ksr_constrainViewToMarginsInParent()

_ = ([self.categoryLabel, self.fundingStackView], self.rootStackView)
|> ksr_addArrangedSubviewsToStackView()
}
}

// MARK: - Styles

private let categoryLabelStyle: LabelStyle = { label in
label
|> \.adjustsFontForContentSizeCategory .~ true
|> \.font .~ UIFont.ksr_title3().bolded
|> \.numberOfLines .~ 0
|> \.textColor .~ .ksr_support_700
}

private let rootStackViewStyle: StackViewStyle = { stackView in
stackView
|> \.axis .~ .vertical
|> \.insetsLayoutMarginsFromSafeArea .~ false
|> \.isLayoutMarginsRelativeArrangement .~ true
|> \.spacing .~ Styles.grid(3)
}

private let fundingStackViewStyle: StackViewStyle = { stackView in
stackView
|> \.axis .~ .vertical
|> \.isLayoutMarginsRelativeArrangement .~ true
|> \.layoutMargins .~ UIEdgeInsets(all: Styles.grid(1))
|> \.spacing .~ Styles.grid(2)
}

private let iconImageStyle: ImageViewStyle = { imageView in
imageView
|> \.tintColor .~ .ksr_create_700
|> \.contentMode .~ .scaleAspectFit
|> \.image .~ Library.image(named: "checkmark")
|> UIImageView.lens.contentHuggingPriority(for: .vertical) .~ .defaultLow
|> UIImageView.lens.contentHuggingPriority(for: .horizontal) .~ .defaultLow
|> UIImageView.lens.contentCompressionResistancePriority(for: .vertical) .~ .required
|> UIImageView.lens.contentCompressionResistancePriority(for: .horizontal) .~ .required
|> \.translatesAutoresizingMaskIntoConstraints .~ false
}

private let optionTextLabelStyle: LabelStyle = { label in
label
|> \.adjustsFontForContentSizeCategory .~ true
|> \.font .~ UIFont.ksr_body()
|> \.numberOfLines .~ 0
|> \.textColor .~ .ksr_support_700
|> \.translatesAutoresizingMaskIntoConstraints .~ false
}