Skip to content

Commit

Permalink
[MBL-983] Already Reported Project Label (#1857)
Browse files Browse the repository at this point in the history
* create ReportProjectCell to display swiftui view

* UITableView cell will be added to the Project Page Table View
* Used to display a new swiftui view for the report this project label and already reported label

* add new cell below overviewSubpages and pass in project's flagging prop

* rename label view

* fix precondition failure: cyclic graph

ReportProjectLabelView (SwiftUI View) re-renders when its text labels contain hyperlinks. Since we're rendering hyperlinks with the helper in Text+HTML.swift, this seems to cause a `precondition failure: cyclic graph` crash. This check prevents that by making sure the cell is only configured once on dequeue.

* layout tableview if needed

needs to be called because we're adding a SwiftUI view to the cell's contentView

* conditionally render labels using `flagged` property

* cleanup

* pass project flagged property along with projectURL to viewcontroller so we know which label can be tappable

* remove temp fix for cyclic graph crash

* update tests

* updateProjectPageViewControllerDataSourceTests  tests

* fix pamphletsubpage cell divider

we don't need to hide it now that there is a new section below it.

* fix view styling on iPad

* formatting

* support more than one hyperlink in a string

* undo change in deprecated file

* update hyperlink urls

* set accessibility traits and cell's traitCollection

* pop views on successful submissionupdate contraint margins
  • Loading branch information
scottkicks committed Sep 28, 2023
1 parent 70dc8b3 commit 8f40c4c
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 65 deletions.
Expand Up @@ -95,6 +95,7 @@ public final class ProjectPageViewController: UIViewController, MessageBannerVie
self.tableView.registerCellClass(ImageViewElementCell.self)
self.tableView.registerCellClass(AudioVideoViewElementCell.self)
self.tableView.registerCellClass(ExternalSourceViewElementCell.self)
self.tableView.registerCellClass(ReportProjectCell.self)
self.tableView.register(nib: .ProjectPamphletMainCell)
self.tableView.register(nib: .ProjectPamphletSubpageCell)
self.tableView.registerCellClass(ProjectRisksCell.self)
Expand Down Expand Up @@ -382,8 +383,9 @@ public final class ProjectPageViewController: UIViewController, MessageBannerVie

self.viewModel.outputs.goToReportProject
.observeForControllerAction()
.observeValues { [weak self] in
self?.goToReportProject(projectUrl: $0)
.observeValues { [weak self] flagged, projectUrl in
guard !flagged else { return }
self?.goToReportProject(projectUrl: projectUrl)
}

self.viewModel.outputs.goToUpdates
Expand Down Expand Up @@ -829,9 +831,9 @@ extension ProjectPageViewController: UITableViewDelegate {
self.viewModel.inputs.tappedComments()
} else if self.dataSource.indexPathIsUpdatesSubpage(indexPath) {
self.viewModel.inputs.tappedUpdates()
} else if self.dataSource.indexPathIsReportProject(indexPath) {
self.viewModel.inputs.tappedReportProject()
}
case ProjectPageViewControllerDataSource.Section.overviewReportProject.rawValue:
self.viewModel.inputs.tappedReportProject()
case ProjectPageViewControllerDataSource.Section.faqsAskAQuestion.rawValue:
self.viewModel.inputs.askAQuestionCellTapped()
case ProjectPageViewControllerDataSource.Section.faqs.rawValue:
Expand Down Expand Up @@ -863,7 +865,9 @@ extension ProjectPageViewController: UITableViewDelegate {

/// If we are displaying the `ProjectPamphletSubpageCell` we do not want to show the cells separator.
self.tableView.separatorStyle = indexPath.section == ProjectPageViewControllerDataSource.Section
.overviewSubpages.rawValue ? .none : .singleLine
.overviewReportProject.rawValue ? .none : .singleLine

self.tableView.layoutIfNeeded()
}

public func tableView(
Expand Down
Expand Up @@ -9,6 +9,7 @@ internal final class ProjectPageViewControllerDataSource: ValueCellDataSource {
case overviewCreatorHeader
case overview
case overviewSubpages
case overviewReportProject
case campaignHeader
case campaign
case faqsHeader
Expand Down Expand Up @@ -104,15 +105,20 @@ internal final class ProjectPageViewControllerDataSource: ValueCellDataSource {

let values: [ProjectPamphletSubpage] = [
.comments(project.stats.commentsCount as Int?, .first),
.updates(project.stats.updatesCount as Int?, .middle),
.reportProject(.last)
.updates(project.stats.updatesCount as Int?, .middle)
]

self.set(
values: values,
cellClass: ProjectPamphletSubpageCell.self,
inSection: Section.overviewSubpages.rawValue
)

self.set(
values: [project.flagging ?? false],
cellClass: ReportProjectCell.self,
inSection: Section.overviewReportProject.rawValue
)
case .campaign:
self.set(
values: [HeaderValue.campaign.description],
Expand Down Expand Up @@ -339,6 +345,8 @@ internal final class ProjectPageViewControllerDataSource: ValueCellDataSource {
cell.configureWith(value: value)
case let (cell as ExternalSourceViewElementCell, value as ExternalSourceViewElement):
cell.configureWith(value: value)
case let (cell as ReportProjectCell, value as Bool):
cell.configureWith(value: value)
default:
assertionFailure("Unrecognized combo: \(cell), \(value)")
}
Expand Down Expand Up @@ -449,10 +457,6 @@ internal final class ProjectPageViewControllerDataSource: ValueCellDataSource {
return (self[indexPath] as? ProjectPamphletSubpage)?.isUpdates == true
}

internal func indexPathIsReportProject(_ indexPath: IndexPath) -> Bool {
return (self[indexPath] as? ProjectPamphletSubpage)?.isReportProject == true
}

internal func isExpandedValuesForFAQsSection() -> [Bool]? {
guard let values = self[section: Section.faqs.rawValue] as? [(ProjectFAQ, Bool)] else { return nil }
return values.map { _, isExpanded in isExpanded }
Expand Down
Expand Up @@ -96,6 +96,8 @@ final class ProjectPageViewControllerDataSourceTests: XCTestCase {
.rawValue
private let overviewSection = ProjectPageViewControllerDataSource.Section.overview.rawValue
private let overviewSubpagesSection = ProjectPageViewControllerDataSource.Section.overviewSubpages.rawValue
private let overviewReportProject = ProjectPageViewControllerDataSource.Section.overviewReportProject
.rawValue
private let faqsHeaderSection = ProjectPageViewControllerDataSource.Section.faqsHeader.rawValue
private let faqsEmptySection = ProjectPageViewControllerDataSource.Section.faqsEmpty.rawValue
private let faqsSection = ProjectPageViewControllerDataSource.Section.faqs.rawValue
Expand Down Expand Up @@ -144,7 +146,7 @@ final class ProjectPageViewControllerDataSourceTests: XCTestCase {
refTag: nil,
isExpandedStates: [false, false, false, false]
)
XCTAssertEqual(9, self.dataSource.numberOfSections(in: self.tableView))
XCTAssertEqual(10, self.dataSource.numberOfSections(in: self.tableView))

// faqsHeader
XCTAssertEqual(
Expand Down Expand Up @@ -200,7 +202,7 @@ final class ProjectPageViewControllerDataSourceTests: XCTestCase {
refTag: nil,
isExpandedStates: [false, false, false, false]
)
XCTAssertEqual(8, self.dataSource.numberOfSections(in: self.tableView))
XCTAssertEqual(9, self.dataSource.numberOfSections(in: self.tableView))

// faqsHeader
XCTAssertEqual(
Expand Down Expand Up @@ -245,7 +247,7 @@ final class ProjectPageViewControllerDataSourceTests: XCTestCase {
project: project,
refTag: nil
)
XCTAssertEqual(9, self.dataSource.numberOfSections(in: self.tableView))
XCTAssertEqual(10, self.dataSource.numberOfSections(in: self.tableView))

// faqsHeader
XCTAssertEqual(
Expand Down Expand Up @@ -300,7 +302,7 @@ final class ProjectPageViewControllerDataSourceTests: XCTestCase {
project: project,
refTag: nil
)
XCTAssertEqual(7, self.dataSource.numberOfSections(in: self.tableView))
XCTAssertEqual(8, self.dataSource.numberOfSections(in: self.tableView))

// faqsHeader
XCTAssertEqual(
Expand Down Expand Up @@ -343,7 +345,7 @@ final class ProjectPageViewControllerDataSourceTests: XCTestCase {
refTag: nil,
isExpandedStates: nil
)
XCTAssertEqual(12, self.dataSource.numberOfSections(in: self.tableView))
XCTAssertEqual(13, self.dataSource.numberOfSections(in: self.tableView))

// risksHeader
XCTAssertEqual(
Expand Down Expand Up @@ -396,7 +398,7 @@ final class ProjectPageViewControllerDataSourceTests: XCTestCase {
refTag: nil,
isExpandedStates: nil
)
XCTAssertEqual(17, self.dataSource.numberOfSections(in: self.tableView))
XCTAssertEqual(18, self.dataSource.numberOfSections(in: self.tableView))

XCTAssertEqual(
1,
Expand Down Expand Up @@ -477,7 +479,7 @@ final class ProjectPageViewControllerDataSourceTests: XCTestCase {
refTag: nil,
isExpandedStates: nil
)
XCTAssertEqual(17, self.dataSource.numberOfSections(in: self.tableView))
XCTAssertEqual(18, self.dataSource.numberOfSections(in: self.tableView))

XCTAssertEqual(
1,
Expand Down Expand Up @@ -551,7 +553,7 @@ final class ProjectPageViewControllerDataSourceTests: XCTestCase {
refTag: nil,
isExpandedStates: nil
)
XCTAssertEqual(20, self.dataSource.numberOfSections(in: self.tableView))
XCTAssertEqual(21, self.dataSource.numberOfSections(in: self.tableView))

// environmentCommitmentsHeader
XCTAssertEqual(
Expand Down Expand Up @@ -607,7 +609,7 @@ final class ProjectPageViewControllerDataSourceTests: XCTestCase {
refTag: nil,
isExpandedStates: nil
)
XCTAssertEqual(20, self.dataSource.numberOfSections(in: self.tableView))
XCTAssertEqual(21, self.dataSource.numberOfSections(in: self.tableView))

// environmentCommitmentsHeader
XCTAssertEqual(
Expand Down Expand Up @@ -659,7 +661,7 @@ final class ProjectPageViewControllerDataSourceTests: XCTestCase {
refTag: nil,
isExpandedStates: nil
)
XCTAssertEqual(5, self.dataSource.numberOfSections(in: self.tableView))
XCTAssertEqual(6, self.dataSource.numberOfSections(in: self.tableView))

// campaign header section
XCTAssertEqual(
Expand Down Expand Up @@ -715,7 +717,7 @@ final class ProjectPageViewControllerDataSourceTests: XCTestCase {
refTag: nil,
isExpandedStates: nil
)
XCTAssertEqual(3, self.dataSource.numberOfSections(in: self.tableView))
XCTAssertEqual(4, self.dataSource.numberOfSections(in: self.tableView))

// overviewCreatorHeader
XCTAssertEqual(
Expand All @@ -731,10 +733,15 @@ final class ProjectPageViewControllerDataSourceTests: XCTestCase {

// overviewSubpages
XCTAssertEqual(
3,
2,
self.dataSource.tableView(self.tableView, numberOfRowsInSection: self.overviewSubpagesSection)
)

XCTAssertEqual(
1,
self.dataSource.tableView(self.tableView, numberOfRowsInSection: self.overviewReportProject)
)

XCTAssertEqual(
"ProjectPamphletMainCell",
self.dataSource.reusableId(item: 0, section: self.overviewSection)
Expand All @@ -743,6 +750,11 @@ final class ProjectPageViewControllerDataSourceTests: XCTestCase {
"ProjectPamphletSubpageCell",
self.dataSource.reusableId(item: 0, section: self.overviewSubpagesSection)
)

XCTAssertEqual(
"ReportProjectCell",
self.dataSource.reusableId(item: 0, section: self.overviewReportProject)
)
}
}

Expand Down Expand Up @@ -818,31 +830,6 @@ final class ProjectPageViewControllerDataSourceTests: XCTestCase {
)
}

func testIndexPathIsReportProjectSubpage() {
let project = Project.template
|> \.displayPrelaunch .~ false
|> \.extendedProjectProperties .~ ExtendedProjectProperties(
environmentalCommitments: [],
faqs: [],
aiDisclosure: nil,
risks: "",
story: self.storyViewableElements,
minimumPledgeAmount: 1
)

self.dataSource.load(
navigationSection: .overview,
project: project,
refTag: nil
)

XCTAssertEqual(
self.dataSource
.indexPathIsReportProject(IndexPath(row: 2, section: self.overviewSubpagesSection)),
true
)
}

func testUpdatingCampaign_WithImageViewElementImage_Success() {
let project = Project.template
|> \.extendedProjectProperties .~ ExtendedProjectProperties(
Expand Down
@@ -0,0 +1,61 @@
import Library
import Prelude
import SwiftUI
import UIKit

internal final class ReportProjectCell: UITableViewCell, ValueCell {
internal func configureWith(value projectFlagged: Bool) {
self.setupTableViewCellStyle(projectFlagged: projectFlagged)
self.setupReportProjectLabelView(projectFlagged: projectFlagged)
}

internal override func layoutSubviews() {
super.layoutSubviews()
}

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

self.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: .greatestFiniteMagnitude)
self.setNeedsLayout()
}

// MARK: - Private Methods

private func setupTableViewCellStyle(projectFlagged: Bool) {
let accessibilityTraits = projectFlagged
? UIAccessibilityTraits.staticText
: UIAccessibilityTraits.button

_ = self
|> baseTableViewCellStyle()
|> ReportProjectCell.lens.accessibilityTraits .~ accessibilityTraits
}

private func setupReportProjectLabelView(projectFlagged: Bool) {
if #available(iOS 15.0, *) {
DispatchQueue.main.async {
let hostingController =
UIHostingController(rootView: ReportProjectLabelView(flagged: projectFlagged))

hostingController.view.translatesAutoresizingMaskIntoConstraints = false
hostingController.view.backgroundColor = .clear

self.contentView.addSubview(hostingController.view)

let leftRightInset = self.traitCollection.isRegularRegular ? Styles.grid(16) : Styles.gridHalf(5)

NSLayoutConstraint.activate([
hostingController.view.topAnchor
.constraint(equalTo: self.contentView.topAnchor, constant: Styles.gridHalf(5)),
hostingController.view.bottomAnchor
.constraint(equalTo: self.contentView.bottomAnchor, constant: -Styles.gridHalf(5)),
hostingController.view.leadingAnchor
.constraint(equalTo: self.contentView.leadingAnchor, constant: leftRightInset),
hostingController.view.trailingAnchor
.constraint(equalTo: self.contentView.trailingAnchor, constant: -leftRightInset)
])
}
}
}
}
@@ -0,0 +1,67 @@
import Library
import SwiftUI

@available(iOS 15.0, *)
struct ReportProjectLabelView: View {
let flagged: Bool

@SwiftUI.Environment(\.horizontalSizeClass) private var horizontalSizeClass

var body: some View {
if flagged {
AlreadyReportedView()
} else {
HStack {
Text(Strings.Report_this_project_to())
.font(Font(UIFont.ksr_body(size: 14)))
.foregroundColor(Color(.ksr_support_700))

Spacer()

Image("chevron-right")
.resizable()
.scaledToFit()
.frame(width: 10, height: 10)
}
.padding(self.horizontalSizeClass == .regular ? 0 : 10)
}
}

private struct AlreadyReportedView: View {
var body: some View {
HStack(alignment: .top, spacing: 10) {
Image("info")
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.foregroundColor(Color(.ksr_support_500))

Text(
html: Strings.It_looks(
our_rules: HelpType.prohibitedItems
.url(withBaseUrl: AppEnvironment.current.apiService.serverConfig.webBaseUrl)?
.absoluteString ?? "",
community_guidelines: HelpType.community
.url(withBaseUrl: AppEnvironment.current.apiService.serverConfig.webBaseUrl)?
.absoluteString ?? ""
),
with: [
ReportProjectHyperLinkType.ourRules.stringLiteral(),
ReportProjectHyperLinkType.communityGuidelines.stringLiteral()
]
)
.font(Font(UIFont.ksr_caption1()))
}
.padding()
.background(Color(.ksr_support_100))
.cornerRadius(15)
}
}
}

@available(iOS 15.0, *)
struct ReportProjectView_Previews: PreviewProvider {
static var previews: some View {
ReportProjectLabelView(flagged: false)
}
}

0 comments on commit 8f40c4c

Please sign in to comment.