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-970] Report Project Info View #1852

Merged
merged 23 commits into from
Sep 23, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d3b513e
add new "Report This Project" row to Project overviewSubpages tablevi…
scottkicks Sep 13, 2023
c46c8d9
navigate to ReportThisProjectInfoView
scottkicks Sep 13, 2023
a23f0ed
formatting
scottkicks Sep 14, 2023
42c426b
create ReportProjectInfoView
scottkicks Sep 18, 2023
36f854d
create ReportProjectInfoView
scottkicks Sep 18, 2023
c2b7914
formatting and cleanup
scottkicks Sep 18, 2023
11e5563
Merge branch 'report-this-project-views' of https://github.com/kickst…
scottkicks Sep 18, 2023
dcfc84e
Merge branch 'main' into report-this-project-views
scottkicks Sep 18, 2023
0d4b397
make Text extension more generic
scottkicks Sep 18, 2023
73cc7a9
Merge branch 'report-this-project-views' of https://github.com/kickst…
scottkicks Sep 18, 2023
63adaba
tests
scottkicks Sep 18, 2023
9596a13
formatting
scottkicks Sep 18, 2023
17b3898
add goToReportProject output test
scottkicks Sep 20, 2023
be5c703
format
scottkicks Sep 20, 2023
3a804c6
Merge branch 'main' into report-this-project-views
scottkicks Sep 20, 2023
806c95d
only pass project url to ReportProjectInfoView
scottkicks Sep 20, 2023
d4a7de4
revert .pbxproj change
scottkicks Sep 20, 2023
7daee5a
move model into KsApi target and replace hardcoded strings
scottkicks Sep 20, 2023
020ee58
refactor List view
scottkicks Sep 20, 2023
256e33a
Merge branch 'report-this-project-views' of https://github.com/kickst…
scottkicks Sep 20, 2023
07f8d0e
Merge branch 'main' into report-this-project-views
scottkicks Sep 20, 2023
0548b41
formatting
scottkicks Sep 20, 2023
bcdf584
Merge branch 'report-this-project-views' of https://github.com/kickst…
scottkicks Sep 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Combine
import KsApi
import Library
import Prelude
import SwiftUI
import UIKit

public enum ProjectPageViewControllerStyles {
Expand Down Expand Up @@ -379,6 +380,12 @@ public final class ProjectPageViewController: UIViewController, MessageBannerVie
self?.goToDashboard(param: param)
}

self.viewModel.outputs.goToReportProject
.observeForControllerAction()
.observeValues { [weak self] in
self?.goToReportProject(project: $0)
}

self.viewModel.outputs.goToUpdates
.observeForControllerAction()
.observeValues { [weak self] in
Expand Down Expand Up @@ -644,6 +651,15 @@ public final class ProjectPageViewController: UIViewController, MessageBannerVie
}
}

private func goToReportProject(project _: Project) {
scottkicks marked this conversation as resolved.
Show resolved Hide resolved
if #available(iOS 15, *) {
let reportProjectInfoView = ReportProjectInfoView()
self.viewModel.inputs.showNavigationBar(false)
Copy link
Contributor

Choose a reason for hiding this comment

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

This might be tied to the weird navigation bar behaviour in the review overview video.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

if you look at goToComments and goToUpdates you'll see that we tell the viewmodel to hide the nav bar before pushing those onto the stack. I think this is because the project page is being presented as a sheet. If we don't manually call self.viewModel.inputs.showNavigationBar(false) then the project page navbar (has the x, share, and heart icons) remains on pushed views.

I'll work on getting the new view's nav title to be inline at the top, but I think this is how we need to do this for now.

self.navigationController?
.pushViewController(UIHostingController(rootView: reportProjectInfoView), animated: true)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess we'll be releasing this with the iOS 17 upgrade?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No this is blocking our next release and needs to go out in 5.11.0.

}

private func goToDashboard(param: Param) {
self.view.window?.rootViewController
.flatMap { $0 as? RootTabBarViewController }
Expand Down Expand Up @@ -807,6 +823,8 @@ 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.faqsAskAQuestion.rawValue:
self.viewModel.inputs.askAQuestionCellTapped()
Expand Down
Copy link
Contributor

Choose a reason for hiding this comment

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

Designs show a disclosure indicator to indicate tappable cell. I don't see one here beside "Report this project to Kickstarter"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've decided to refactor this label to be it's own swiftUI view to make it easier to toggle between this and the "you've already reported" label in my next PR (MBL-983).

I'll be sure to include a disclosure indicator in that.

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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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 @@ -104,7 +104,8 @@ internal final class ProjectPageViewControllerDataSource: ValueCellDataSource {

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

self.set(
Expand Down Expand Up @@ -448,6 +449,10 @@ 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
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ final class ProjectPageViewControllerDataSourceTests: XCTestCase {

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

Expand Down Expand Up @@ -818,6 +818,31 @@ 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
99 changes: 99 additions & 0 deletions Kickstarter-iOS/Features/ReportProject/ReportProjectInfoView.swift
scottkicks marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import Library
import SwiftUI

enum ReportProjectHyperLinkType: String, CaseIterable {
case prohibitedItems
case communityGuidelines

func stringLiteral() -> String {
switch self {
case .prohibitedItems:
return Strings.Prohibited_items()
case .communityGuidelines:
return "community guidelines"
Copy link
Contributor

Choose a reason for hiding this comment

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

No internationalized text for this from when Android did it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don't have an internationalized string for this, unfortunately. This is mainly for the hyperlink. I'm not sure how Android handles hyperlinks, but they wouldn't have an internationalized string. I'll request one from the translations team, but those may not be done by code freeze.

Seems like something that shouldn't hold up this release. What do you think?

}
}
}

@available(iOS 15, *)
struct ReportProjectInfoView: View {
var body: some View {
NavigationView {
VStack(alignment: .leading, spacing: 10) {
Text(Strings.Report_this_project())
.font(Font(UIFont.ksr_title1()))
.bold()
.padding()
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this should be a separate nav title under the navigation bar. I think the back button and the title should be on the same navigation bar. It should look like "Updates" or "Comments".


List(listItems, children: \.subItems) { item in
RowView(item: item)
}
.navigationBarHidden(true)
.listStyle(.inset)
.tint(Color(.ksr_create_700))
}
}
}
}

// MARK: - Views

@available(iOS 15, *)
private struct BaseRowView: View {
var item: ReportProjectInfoListItem

var body: some View {
VStack(spacing: 0) {
Text(item.title)
.font(item.type == .parent ? Font(UIFont.ksr_body()) : Font(UIFont.ksr_callout()))
.bold()
.frame(maxWidth: .infinity, alignment: .leading)

if let hyperLink = hyperLink(in: item.subtitle) {
Text(html: item.subtitle, with: hyperLink.stringLiteral())
.font(item.type == .parent ? Font(UIFont.ksr_subhead()) : Font(UIFont.ksr_subhead(size: 14)))
scottkicks marked this conversation as resolved.
Show resolved Hide resolved
.frame(maxWidth: .infinity, alignment: .leading)
} else {
Text(item.subtitle)
.font(item.type == .parent ? Font(UIFont.ksr_subhead()) : Font(UIFont.ksr_subhead(size: 14)))
.frame(maxWidth: .infinity, alignment: .leading)
}
}
}
}

@available(iOS 15, *)
struct RowView: View {
var item: ReportProjectInfoListItem

var body: some View {
if item.type == .child {
// TODO: Push Submission Form View In MBL-971(https://kickstarter.atlassian.net/browse/MBL-971)
NavigationLink(destination: { Text("submit report view") }, label: { BaseRowView(item: item) })
Copy link
Contributor

Choose a reason for hiding this comment

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

Internationlized text for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is just a placeholder for the new view that will actually be pushed

} else {
BaseRowView(item: item)
}
}
}

// MARK: - Private Methods

/// Returns a ReportProjectHyperLinkType if the given string contains a type's string literal
private func hyperLink(in string: String) -> ReportProjectHyperLinkType? {
for linkType in ReportProjectHyperLinkType.allCases {
Copy link
Contributor

Choose a reason for hiding this comment

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

Would a .first(where function be cleaner and more readable than a for loop?

if string.lowercased().contains(linkType.stringLiteral().lowercased()) {
return linkType
}
}

return nil
}

// MARK: - Preview

@available(iOS 15, *)
struct ReportProjectInfoView_Previews: PreviewProvider {
static var previews: some View {
ReportProjectInfoView()
}
}
scottkicks marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import Foundation
import Library

enum ReportProjectInfoListItemType {
case child
case parent
}

struct ReportProjectInfoListItem: Identifiable {
var type: ReportProjectInfoListItemType
var id = UUID()
var title: String
var subtitle: String
var subItems: [ReportProjectInfoListItem]?
var exampleMenuItems: [ReportProjectInfoListItem]?
}

/// Hierarchical structure of the ReportProjectInfo List View
let listItems =
[
ReportProjectInfoListItem(
type: .parent,
title: Strings.This_project_breaks(),
subtitle: Strings
.Projects_may_not_offer(prohibited_items: "https://www.kickstarter.com/rules/prohibited?ref=project-page-report"),
subItems: thisProjecBreaksSubListItems
scottkicks marked this conversation as resolved.
Show resolved Hide resolved
),
ReportProjectInfoListItem(
type: .parent,
title: Strings.Report_spam(),
subtitle: Strings
.Our(community_guidelines: "https://www.kickstarter.com/help/community?ref=project-page-report"),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do we have these URLs somewhere in the app already? I wasn't seeing them and I'd rather not hard code these if we can avoid it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Try to use existing methods of placing urls like HelpType url(withBaseUrl

Copy link
Contributor

Choose a reason for hiding this comment

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

Recent example use case was the ProjectTabDisclaimerCell

subItems: reportSpamSubListItems

),
ReportProjectInfoListItem(
type: .parent,
title: Strings.Intellectual_property_violation(),
subtitle: Strings.A_project_is_infringing(),
subItems: intellectualProperySubListItems
)
]

//// Sub items for This project breaks Our Rules
let thisProjecBreaksSubListItems =
[
ReportProjectInfoListItem(
type: .child,
title: Strings.Copying_reselling(),
subtitle: Strings.Projects_cannot_plagiarize()
),
ReportProjectInfoListItem(
type: .child,
title: Strings.Prototype_misrepresentation(),
subtitle: Strings.Creators_must_be_transparent()
),
ReportProjectInfoListItem(
type: .child,
title: Strings.Suspicious_creator_behavior(),
subtitle: Strings.Project_creators_and_their()
),
ReportProjectInfoListItem(
type: .child,
title: Strings.Not_raising_funds(),
subtitle: Strings.Projects_on()
)
]

//// Sub items for Report spam
let reportSpamSubListItems = [
ReportProjectInfoListItem(
type: .child,
title: Strings.Spam(),
subtitle: Strings.Ex_using()
),
ReportProjectInfoListItem(
type: .child,
title: Strings.Abuse(),
subtitle: Strings.Ex_posting()
)
]

//// Sub items for intellectual property
let intellectualProperySubListItems = [
ReportProjectInfoListItem(
type: .child,
title: Strings.Intellectual_property_violation(),
subtitle: Strings.Kickstarter_takes_claims()
)
]
Loading